From b3c60ebfaa41d49a0437c43f0e2be86f221fd7bf Mon Sep 17 00:00:00 2001 From: Arc <33088785+arcbtc@users.noreply.github.com> Date: Mon, 3 Mar 2025 20:31:34 +0000 Subject: [PATCH 01/13] ugrade to lnbits v1 (#8) * fix nwc description * initial * fixup crud and models * views and tasks * Added description for extension preview * fixed js * make * Allow arbitrary types * trying to fix install error * added arbitrary_types_allowed * fixed migration error * migration fix * migration fix attempt * make * hopefully his will work * removed basemodel (test) * Update manifest.json * fix json bug, move js to own file * move admin js to own file * update dev environment * fix template regression * upgrade quasar api calls * fix models * fix budget * fix tracked budget * fix async pytests * mount docker socket for integration test * install pytest-asyncio in poetry env * update integration tests * revert listener refactoring to avoid cyclic dependency hell * fix broken refactoring * fix for new api * fix integration test run * fix integration test run? * fix integration test run? * fix integration test run? * fix integration test run? * edges hardening * fix integration test run? * more hardening * fix for ghactions ? * fix ghactions? * more ghaction fixes * fix integration test run? * more hardening * garbage collect old tracked events * configurable handle_missed_events * readme format * default handle_missed_events to 0 * more hardening * increase timeout * increase timeout * Add more tests * more hardening * format * lint * postgres fix --------- Co-authored-by: Riccardo Balbo --- .devcontainer/devcontainer.json | 6 +- .devcontainer/pre-setup.sh | 10 + .devcontainer/setup.sh | 11 +- .github/workflows/test.yml | 6 +- Makefile | 4 +- README.md | 19 +- __init__.py | 15 +- config.json | 20 +- crud.py | 321 +++-- description.md | 3 + manifest.json | 2 +- migrations.py | 32 +- models.py | 52 +- nwcp.py | 62 +- paranoia.py | 170 +++ poetry.lock | 1999 ++++++++++++++++-------------- pyproject.toml | 23 +- static/js/admin.js | 87 ++ static/js/index.js | 386 ++++++ tasks.py | 160 ++- templates/nwcprovider/admin.html | 114 +- templates/nwcprovider/index.html | 413 +----- tests/integration/.env | 2 +- tests/integration/data.zip | Bin 69158 -> 75937 bytes tests/integration/start.sh | 34 +- tests/integration/test_all.py | 143 ++- tests/unit/test_nwcp.py | 9 +- toc.md | 29 + views.py | 9 +- views_api.py | 111 +- 30 files changed, 2544 insertions(+), 1708 deletions(-) create mode 100644 .devcontainer/pre-setup.sh create mode 100644 description.md create mode 100644 paranoia.py create mode 100644 static/js/admin.js create mode 100644 static/js/index.js create mode 100644 toc.md diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 004c593..ab3aa91 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,20 +1,20 @@ { "name": "lnbits_nwc_provider", - "image": "mcr.microsoft.com/devcontainers/python:1-3.9-bullseye", + "image": "mcr.microsoft.com/devcontainers/python:1-3.12", "features": { "ghcr.io/devcontainers-contrib/features/poetry:2": {} }, "mounts": [ "source=${localWorkspaceFolder}/.devcontainer/start.sh,target=/start-lnbits.sh,type=bind", "source=${localWorkspaceFolder}/.devcontainer/setup.sh,target=/setup.sh,type=bind", + "source=${localWorkspaceFolder}/.devcontainer/pre-setup.sh,target=/pre-setup.sh,type=bind", "source=/var/run/docker.sock,target=/var/run/docker.sock,type=bind" ], "containerEnv": { "IS_DEV_CONTAINER": "true" }, - "postCreateCommand": "/bin/bash /setup.sh ${containerWorkspaceFolder}", + "postCreateCommand": "/bin/bash /pre-setup.sh && /bin/bash /setup.sh ${containerWorkspaceFolder}", "postStartCommand": "/bin/bash /start-lnbits.sh", - "forwardPorts": [5000], "customizations": { "vscode": { "settings": { diff --git a/.devcontainer/pre-setup.sh b/.devcontainer/pre-setup.sh new file mode 100644 index 0000000..367a1e1 --- /dev/null +++ b/.devcontainer/pre-setup.sh @@ -0,0 +1,10 @@ +#!/bin/bash +set -e + +sudo apt update -y +sudo apt install -y curl +sudo apt-get install -y docker.io + +curl -fsSL https://deb.nodesource.com/setup_20.x -o /tmp/nodesource_setup.sh +sudo bash /tmp/nodesource_setup.sh +sudo apt-get install -y nodejs diff --git a/.devcontainer/setup.sh b/.devcontainer/setup.sh index 6151741..d2a2f72 100644 --- a/.devcontainer/setup.sh +++ b/.devcontainer/setup.sh @@ -2,13 +2,6 @@ echo $PYTHONPATH CONTAINER_WORKSPACE_FOLDER=$1 cd $CONTAINER_WORKSPACE_FOLDER -sudo apt update -y -sudo apt install -y python3.9-distutils curl -sudo apt-get install -y docker.io - -curl -fsSL https://deb.nodesource.com/setup_20.x -o /tmp/nodesource_setup.sh -sudo bash /tmp/nodesource_setup.sh -sudo apt-get install -y nodejs cd $HOME echo $PWD @@ -17,8 +10,8 @@ if [ ! -d ./lnbits ] ; then fi cd lnbits echo $PWD -git checkout 0.12.8 -poetry env use python3.9 +git checkout v1.0.0-rc7 +poetry env use 3.12 POETRY_PYTHON_PATH=$(poetry env info -p)/bin/python ln -sf $POETRY_PYTHON_PATH /home/vscode/python make bundle diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d9c1264..e720631 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -32,11 +32,14 @@ jobs: cd $HOME/lnbits poetry_env_path=$(poetry env info --path) source $poetry_env_path/bin/activate + pip install pytest-asyncio cd $cdir pytest tests/unit/*.py -s - name: Setup integration tests - run: bash tests/integration/start.sh + run: | + export HEADLESS=1 + bash tests/integration/start.sh - name: Run integration tests run: | @@ -44,5 +47,6 @@ jobs: cd $HOME/lnbits poetry_env_path=$(poetry env info --path) source $poetry_env_path/bin/activate + pip install pytest-asyncio cd $cdir pytest tests/integration/*.py -s diff --git a/Makefile b/Makefile index fb619f0..9a08146 100644 --- a/Makefile +++ b/Makefile @@ -33,7 +33,7 @@ checkeditorconfig: test: PYTHONUNBUFFERED=1 \ DEBUG=true \ - poetry run pytest tests/unit/*.py -s + poetry run pytest install-pre-commit-hook: @echo "Installing pre-commit hook to git" @echo "Uninstall the hook with poetry run pre-commit uninstall" @@ -44,4 +44,4 @@ pre-commit: checkbundle: - @echo "skipping checkbundle" \ No newline at end of file + @echo "skipping checkbundle" diff --git a/README.md b/README.md index 605ec9d..24eb404 100644 --- a/README.md +++ b/README.md @@ -12,11 +12,20 @@ Configure the extension from the "Settings" page in the top right menu when logg ### Configuration Options: -| Key | Description | Default | -| ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | -| relay | URL of the nostr relay for dispatching and receiving NWC events. Use public relays or a custom one. Specify `nostrclient` to connect to the [nostrclient extension](https://github.com/lnbits/nostrclient). | nostrclient | -| provider_key | Nostr secret key of the NWC Service Provider. | Random key generated on install | -| relay_alias | Relay URL to display in pairing URLs. Set if different from `relay`. | Empty (uses the `relay` value) | +| Key | Description | Default | +| -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | +| relay | URL of the nostr relay for dispatching and receiving NWC events. Use public relays or a custom one. Specify `nostrclient` to connect to the [nostrclient extension](https://github.com/lnbits/nostrclient). | nostrclient | +| provider_key | Nostr secret key of the NWC Service Provider. | Random key generated on install | +| relay_alias | Relay URL to display in pairing URLs. Set if different from `relay`. | Empty (uses the `relay` value) | +| handle_missed_events | Number of seconds to look back for processing events missed while offline. Setting it to 0 disables this functionality. | 0 | + +> [!WARNING] +> +> Do not change `handle_missed_events` from its default value of `0` unless you fully understand its implications. +> While a non-zero value may improve service quality under unstable conditions (e.g., poor connectivity or unreliable power), it can also lead to unexpected behavior. +> For example, in shared or community lnbits instances, where users are unaware of this functionality, they might assume a payment has failed and attempt to pay a new invoice with a different wallet, only for the instance to come back online and process the original payment request, potentially leading to duplicate payments. +> +> For this reason, unless you are trying to tackle this specific issue, it is recommended to leave this setting at `0`. ### Using Nostrclient diff --git a/__init__.py b/__init__.py index f0adf33..86e59d7 100644 --- a/__init__.py +++ b/__init__.py @@ -1,17 +1,14 @@ import asyncio from fastapi import APIRouter -from loguru import logger - from lnbits.tasks import create_permanent_unique_task +from loguru import logger from .crud import db from .tasks import handle_execution_queue, handle_nwc from .views import nwcprovider_router from .views_api import nwcprovider_api_router -scheduled_tasks: list[asyncio.Task] = [] - nwcprovider_ext: APIRouter = APIRouter( prefix="/nwcprovider", tags=["NWC Service Provider"] ) @@ -25,6 +22,8 @@ } ] +scheduled_tasks: list[asyncio.Task] = [] + def nwcprovider_stop(): for task in scheduled_tasks: @@ -43,4 +42,10 @@ def nwcprovider_start(): scheduled_tasks.append(task) -__all__ = ["db"] +__all__ = [ + "db", + "nwcprovider_ext", + "nwcprovider_static_files", + "nwcprovider_start", + "nwcprovider_stop", +] diff --git a/config.json b/config.json index 66d391d..92b27df 100644 --- a/config.json +++ b/config.json @@ -2,13 +2,31 @@ "name": "NWC Service Provider", "short_description": "A NWC service provider for LNbits", "tile": "/nwcprovider/static/image/nwcprovider.png", - "min_lnbits_version": "0.12.5", + "min_lnbits_version": "1.0.0", "contributors": [ { "name": "Riccardo Balbo", "uri": "https://github.com/riccardobl", + "role": "Lead Dev" + }, + { + "name": "Ben Arc", + "uri": "https://github.com/arcbtc", "role": "Dev" } ], + "images": [ + { + "uri": "https://raw.githubusercontent.com/riccardobl/nwcprovider/main/static/image/1.png" + }, + { + "uri": "https://raw.githubusercontent.com/riccardobl/nwcprovider/main/static/image/2.png" + }, + { + "uri": "https://raw.githubusercontent.com/riccardobl/nwcprovider/main/static/image/3.png" + } + ], + "description_md": "https://raw.githubusercontent.com/riccardobl/nwcprovider/main/description.md", + "terms_and_conditions_md": "https://raw.githubusercontent.com/riccardobl/nwcprovider/main/toc.md", "license": "MIT" } diff --git a/crud.py b/crud.py index 806cbf2..ee50849 100644 --- a/crud.py +++ b/crud.py @@ -4,174 +4,243 @@ from lnbits.db import Database from .execution_queue import enqueue -from .models import NWCBudget, NWCKey, NWCNewBudget +from .models import ( + CreateNWCKey, + DeleteNWC, + GetBudgetsNWC, + GetNWC, + GetWalletNWC, + NWCBudget, + NWCKey, + NWCNewBudget, + TrackedSpendNWC, +) +from .paranoia import ( + assert_sane_string, + assert_valid_expiration_seconds, + assert_valid_msats, + assert_valid_positive_int, + assert_valid_pubkey, + assert_valid_timestamp_seconds, + assert_valid_wallet_id, +) db = Database("ext_nwcprovider") -async def create_nwc( - pubkey: str, - wallet_id: str, - description: str, - expires_at: int, - permissions: List[str], - budgets: Optional[List[NWCNewBudget]] = None, -) -> NWCKey: - # Check if the key already exists - if await get_nwc(pubkey, None, True): - raise Exception("Public key already used") - # If not, create it - now = int(time.time()) - await db.execute( - """ - INSERT INTO nwcprovider.keys ( - pubkey, - wallet, - description, - permissions, - created_at, - expires_at, - last_used - ) - VALUES (?, ?, ?, ?, ?, ?, ?) - """, - ( - pubkey, - wallet_id, - description, - " ".join(permissions), - now, - int(expires_at) if expires_at else 0, - now, - ), +async def create_nwc(data: CreateNWCKey) -> NWCKey: + + # hardening # + assert_valid_pubkey(data.pubkey) + assert_valid_wallet_id(data.wallet) + assert_sane_string(data.description) + assert_valid_expiration_seconds(data.expires_at) + for permission in data.permissions: + assert_sane_string(permission) + + if data.budgets: + for budget in data.budgets: + assert_valid_msats(budget.budget_msats) + assert_valid_positive_int(budget.refresh_window) + assert_valid_timestamp_seconds(budget.created_at) + # ## # + + nwckey_entry = NWCKey( + pubkey=data.pubkey, + wallet=data.wallet, + description=data.description, + expires_at=int(data.expires_at) if data.expires_at else 0, + permissions=" ".join(data.permissions), + created_at=int(time.time()), + last_used=int(time.time()), ) - # Add budgets - if budgets: - for budget in budgets: - await db.execute( - """ - INSERT INTO nwcprovider.budgets ( - pubkey, - budget_msats, - refresh_window, - created_at - ) - VALUES (?, ?, ?, ?) - """, - (pubkey, budget.budget_msats, budget.refresh_window, budget.created_at), + await db.insert("nwcprovider.keys", nwckey_entry) + if data.budgets: + for budget in data.budgets: + budget_entry = NWCNewBudget( # fixme + pubkey=data.pubkey, + budget_msats=budget.budget_msats, + refresh_window=budget.refresh_window, + created_at=budget.created_at, ) - # Return the created key - return NWCKey( - pubkey=pubkey, - wallet=wallet_id, - description=description, - expires_at=expires_at, - permissions=" ".join(permissions), - created_at=now, - last_used=now, - ) + await db.insert("nwcprovider.budgets", budget_entry) + return NWCKey(**nwckey_entry.dict()) + +async def delete_nwc(data: DeleteNWC) -> None: + + # hardening # + assert_valid_pubkey(data.pubkey) + assert_valid_wallet_id(data.wallet) + # ## # -async def delete_nwc(pubkey: str, wallet_id: str): - nwc = await get_nwc(pubkey, wallet_id) - if not nwc: - raise Exception("Public key does not exist") await db.execute( - """ - DELETE FROM nwcprovider.keys WHERE pubkey = ? AND wallet = ? - """, - (pubkey, wallet_id), + "DELETE FROM nwcprovider.keys WHERE pubkey = :pubkey AND wallet = :wallet", + {"pubkey": data.pubkey, "wallet": data.wallet}, ) -async def get_wallet_nwcs( - wallet_id: str, include_expired: Optional[bool] = False -) -> List[NWCKey]: - rows = await db.fetchall( +async def get_wallet_nwcs(data: GetWalletNWC) -> List[NWCKey]: + expires = int(time.time()) if not data.include_expired else -1 + + # hardening # + assert_valid_wallet_id(data.wallet) + assert_valid_expiration_seconds(expires) + # ## # + + return await db.fetchall( """ SELECT * FROM nwcprovider.keys - WHERE wallet = ? AND (expires_at = 0 OR expires_at > ?) + WHERE wallet = :wallet AND (expires_at = 0 OR expires_at > :expires) """, - (wallet_id, int(time.time()) if not include_expired else -1), + { + "wallet": data.wallet, + "expires": expires, + }, + model=NWCKey, ) - return [NWCKey(**row) for row in rows] -async def get_nwc( - pubkey: str, - wallet_id: Optional[str] = None, - include_expired: Optional[bool] = False, - refresh_last_used: Optional[bool] = False, -) -> Optional[NWCKey]: +async def get_nwc(data: GetNWC) -> Optional[NWCKey]: + expires = int(time.time()) if not data.include_expired else -1 + + # hardening # + assert_valid_pubkey(data.pubkey) + assert_valid_expiration_seconds(expires) + # ## # + # expires_at = 0 means it never expires - if wallet_id: + if data.wallet: + assert_valid_wallet_id(data.wallet) row = await db.fetchone( """ SELECT * FROM nwcprovider.keys - WHERE pubkey = ? AND wallet = ? AND (expires_at = 0 OR expires_at > ?) + WHERE pubkey = :pubkey AND wallet = :wallet + AND (expires_at = 0 OR expires_at > :expires) """, - (pubkey, wallet_id, int(time.time()) if not include_expired else -1), + { + "pubkey": data.pubkey, + "wallet": data.wallet, + "expires": expires, + }, + NWCKey, ) else: row = await db.fetchone( """ SELECT * FROM nwcprovider.keys - WHERE pubkey = ? AND (expires_at = 0 OR expires_at > ?) + WHERE pubkey = :pubkey AND (expires_at = 0 OR expires_at > :expires) """, - (pubkey, int(time.time()) if not include_expired else -1), + { + "pubkey": data.pubkey, + "expires": expires, + }, + NWCKey, ) if not row: return None - if refresh_last_used: + if data.refresh_last_used: await db.execute( """ - UPDATE nwcprovider.keys SET last_used = ? WHERE pubkey = ? + UPDATE nwcprovider.keys SET last_used = + :last_used WHERE pubkey = :pubkey """, - (int(time.time()), pubkey), + {"last_used": int(time.time()), "pubkey": data.pubkey}, ) - return NWCKey(**row) + return row + + +async def get_budgets_nwc(data: GetBudgetsNWC) -> Optional[NWCBudget]: + # hardening # + assert_valid_pubkey(data.pubkey) + # ## # -async def get_budgets_nwc(pubkey, calculate_spent=False): rows = await db.fetchall( - "SELECT * FROM nwcprovider.budgets WHERE pubkey = ?", (pubkey) + "SELECT * FROM nwcprovider.budgets WHERE pubkey = :pubkey", + {"pubkey": data.pubkey}, ) budgets = [NWCBudget(**row) for row in rows] - if calculate_spent: + if data.calculate_spent: for budget in budgets: last_cycle, next_cycle = budget.get_timestamp_range() + + # hardening # + assert_valid_timestamp_seconds(last_cycle) + assert_valid_timestamp_seconds(next_cycle) + # ## # + tot_spent_in_range_msats = await db.fetchone( """ SELECT SUM(amount_msats) FROM nwcprovider.spent - WHERE pubkey = ? AND created_at >= ? AND created_at < ? + WHERE pubkey = :pubkey AND created_at >= + :last_cycle AND created_at < :next_cycle """, - (pubkey, last_cycle, next_cycle), + { + "pubkey": data.pubkey, + "last_cycle": last_cycle, + "next_cycle": next_cycle, + }, ) - tot_spent_in_range_msats = tot_spent_in_range_msats[0] or 0 + tot_spent_in_range_msats = ( + next(iter(tot_spent_in_range_msats.values())) or 0 + ) + + # hardening # + assert_valid_msats(tot_spent_in_range_msats) + # ## # + budget.used_budget_msats = tot_spent_in_range_msats return budgets -async def tracked_spend_nwc(pubkey: str, amount_msats: int, action): +async def tracked_spend_nwc(data: TrackedSpendNWC, action): async def r(): + + # hardening # + assert_valid_pubkey(data.pubkey) + assert_valid_msats(data.amount_msats) + # ## # + created_at = int(time.time()) - budgets = await get_budgets_nwc(pubkey) + budgets = await get_budgets_nwc(GetBudgetsNWC(pubkey=data.pubkey)) in_budget = True for budget in budgets: last_cycle, next_cycle = budget.get_timestamp_range() + + # hardening # + assert_valid_timestamp_seconds(last_cycle) + assert_valid_timestamp_seconds(next_cycle) + # ## # + tot_spent_in_range_msats = ( - ( - await db.fetchone( - """ - SELECT SUM(amount_msats) FROM nwcprovider.spent - WHERE pubkey = ? AND created_at >= ? AND created_at < ? - """, - (pubkey, last_cycle, next_cycle), + next( + iter( + ( + await db.fetchone( + """ + SELECT SUM(amount_msats) FROM nwcprovider.spent + WHERE pubkey = :pubkey AND created_at >= + :last_cycle AND created_at < :next_cycle + """, + { + "pubkey": data.pubkey, + "last_cycle": last_cycle, + "next_cycle": next_cycle, + }, + ) + ).values() ) - )[0] + ) or 0 ) - if tot_spent_in_range_msats + amount_msats > budget.budget_msats: + + # hardening # + assert_valid_msats(tot_spent_in_range_msats) + assert_valid_msats(budget.budget_msats) + # ## # + + if tot_spent_in_range_msats + data.amount_msats > budget.budget_msats: in_budget = False break if not in_budget: @@ -180,9 +249,13 @@ async def r(): await db.execute( """ INSERT INTO nwcprovider.spent (pubkey, amount_msats, created_at) - VALUES (?, ?, ?) + VALUES (:pubkey, :amount_msats, :created_at) """, - (pubkey, amount_msats, created_at), + { + "pubkey": data.pubkey, + "amount_msats": data.amount_msats, + "created_at": created_at, + }, ) return True, out @@ -190,29 +263,31 @@ async def r(): async def get_config_nwc(key: str): - row = await db.fetchone("SELECT * FROM nwcprovider.config WHERE key = ?", (key,)) + row = await db.fetchone( + "SELECT * FROM nwcprovider.config WHERE key = :key", {"key": key} + ) if not row: return None return row["value"] -async def get_all_config_nwc(): - rows = await db.fetchall("SELECT * FROM nwcprovider.config") - return {row["key"]: row["value"] for row in rows} +async def set_config_nwc(key: str, value: str): + # hardening # + assert_sane_string(key) + assert_sane_string(value) + # ## # -async def set_config_nwc(key: str, value: str): - await db.execute( - """ - DELETE FROM nwcprovider.config - WHERE key = ? - """, - (key,), - ) await db.execute( """ INSERT INTO nwcprovider.config (key, value) - VALUES (?, ?) + VALUES (:key, :value) + ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value; """, - (key, value), + {"key": key, "value": value}, ) + + +async def get_all_config_nwc(): + rows = await db.fetchall("SELECT * FROM nwcprovider.config") + return {row["key"]: row["value"] for row in rows} diff --git a/description.md b/description.md new file mode 100644 index 0000000..bc65726 --- /dev/null +++ b/description.md @@ -0,0 +1,3 @@ +NWC Service Provider Extension for https://github.com/lnbits/lnbits + +Easily connect your LNbits wallets via https://nwc.dev/ diff --git a/manifest.json b/manifest.json index 6a77c95..eea77ee 100644 --- a/manifest.json +++ b/manifest.json @@ -2,7 +2,7 @@ "repos": [ { "id": "nwcprovider", - "organisation": "riccardobl", + "organisation": "lnbits", "repository": "nwcprovider" } ] diff --git a/migrations.py b/migrations.py index cad19a5..fd12650 100644 --- a/migrations.py +++ b/migrations.py @@ -68,15 +68,17 @@ async def m003_default_config(db): """ await db.execute( """ - INSERT INTO nwcprovider.config (key, value) VALUES ('relay', 'nostrclient'); + INSERT INTO nwcprovider.config (key, value) VALUES ('relay', 'nostrclient') + ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value; """ ) new_private_key = bytes.hex(secp256k1._gen_private_key()) await db.execute( """ - INSERT INTO nwcprovider.config (key, value) VALUES ('provider_key', ?); + INSERT INTO nwcprovider.config (key, value) VALUES ('provider_key', :provider_key) + ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value; """, - (new_private_key,), + {"provider_key": new_private_key}, ) @@ -84,14 +86,13 @@ async def m004_default_config2(db): """ Default config """ - await db.execute( - """ - INSERT INTO nwcprovider.config (key, value) VALUES ('relay_alias', ?); + """ + INSERT INTO nwcprovider.config (key, value) VALUES ('relay_alias', :value) + ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value; """, - ("",), - ) - + {"value": ""}, + ) async def m005_key_last_used(db): """ @@ -102,3 +103,16 @@ async def m005_key_last_used(db): ALTER TABLE nwcprovider.keys ADD COLUMN last_used INTEGER; """ ) + + +async def m006_default_config3(db): + """ + Default config + """ + await db.execute( + """ + INSERT INTO nwcprovider.config (key, value) VALUES ('handle_missed_events', :value) + ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value; + """, + {"value": "0"}, + ) diff --git a/models.py b/models.py index 83f0b2a..2208d98 100644 --- a/models.py +++ b/models.py @@ -2,7 +2,7 @@ import time from sqlite3 import Row -from typing import Any, Dict, List +from typing import Any, Dict, List, Optional from pydantic import BaseModel @@ -52,23 +52,51 @@ def from_row(cls, row: Row) -> "NWCBudget": return cls(**dict(row)) -class NWCLog(BaseModel): - id: int - pubkey: str - payload: str - created_at: int - - @classmethod - def from_row(cls, row: Row) -> "NWCLog": - return cls(**dict(row)) - - class NWCNewBudget(BaseModel): + pubkey: Optional[str] budget_msats: int refresh_window: int created_at: int +# CRUD models +class CreateNWCKey(BaseModel): + pubkey: str + wallet: str + description: str + expires_at: int + permissions: List[str] + budgets: Optional[List[NWCNewBudget]] = None + + +class DeleteNWC(BaseModel): + pubkey: str + wallet: Optional[str] = None + + +class GetWalletNWC(BaseModel): + wallet: Optional[str] = None + include_expired: Optional[bool] = False + + +class GetNWC(BaseModel): + pubkey: str + wallet: Optional[str] = None + include_expired: Optional[bool] = False + refresh_last_used: Optional[bool] = False + + +class GetBudgetsNWC(BaseModel): + pubkey: str + calculate_spent: Optional[bool] = False + + +class TrackedSpendNWC(BaseModel): + pubkey: str + amount_msats: int + + +# API models class NWCRegistrationRequest(BaseModel): permissions: List[str] description: str diff --git a/nwcp.py b/nwcp.py index 50f6ae7..4a5023a 100644 --- a/nwcp.py +++ b/nwcp.py @@ -47,9 +47,37 @@ def register_response(self, event_id: str): if event_id not in self.responses: self.responses.append(event_id) + def gc(self, expire: Optional[int] = None): + """ + Garbage collection, remove all the events that have a response older + than expire seconds (defaults to 1 hour if 0 or None) + """ + expire = expire or 1 * 60 * 60 + now = int(time.time()) + deleted_ids = [] + for [event_id, event] in self.events.items(): + if event_id in self.responses: + if now - event["created_at"] > expire: + del self.events[event_id] + deleted_ids.append(event_id) + self.responses = [ + event_id for event_id in self.responses if event_id not in deleted_ids + ] + + if len(deleted_ids) > 0: + logger.debug("Garbage collected " + str(len(deleted_ids)) + " events") + + class Config: + arbitrary_types_allowed = True + class NWCServiceProvider: - def __init__(self, private_key: Optional[str] = None, relay: Optional[str] = None): + def __init__( + self, + private_key: Optional[str] = None, + relay: Optional[str] = None, + handle_missed_events: int = 0, + ): if not relay: # Connect to nostrclient relay = "nostrclient" if relay == "nostrclient": @@ -81,7 +109,7 @@ def __init__(self, private_key: Optional[str] = None, relay: Optional[str] = Non self.request_listeners: Dict[ str, Callable[ - ["NWCServiceProvider", str, Dict], + [NWCServiceProvider, str, Dict], Awaitable[List[Tuple[Optional[Dict], Optional[Dict], List]]], ], ] = {} @@ -89,6 +117,9 @@ def __init__(self, private_key: Optional[str] = None, relay: Optional[str] = Non # Reconnect task (if the connection is lost) self.reconnect_task = None + # Garbage collection loop + self.gc_task = None + # Subscription self.sub = None self.rate_limit: Dict[str, RateLimit] = {} @@ -102,6 +133,11 @@ def __init__(self, private_key: Optional[str] = None, relay: Optional[str] = Non # if True the instance is shutting down self.shutdown = False + # process missed events that are not older than + # handle_missed_events seconds (0 to disable) + # (handles reboots) + self.handle_missed_events = handle_missed_events + logger.info( "NWC Service is ready. relay: " + str(self.relay) @@ -109,6 +145,12 @@ def __init__(self, private_key: Optional[str] = None, relay: Optional[str] = Non + self.public_key_hex ) + async def _gc_loop(self): + while not self._is_shutting_down(): + if self.sub: + self.sub.gc(self.handle_missed_events) + await asyncio.sleep(60) + def get_supported_methods(self): """ Returns the list of supported methods by this service provider. @@ -141,6 +183,7 @@ async def start(self): Starts the NWC service provider. """ self.reconnect_task = asyncio.create_task(self._connect_to_relay()) + self.gc_task = asyncio.create_task(self._gc_loop()) def _json_dumps(self, data: Union[Dict, list]) -> str: """ @@ -231,15 +274,15 @@ async def _subscribe(self): req_filter = { "kinds": [23194], "#p": [self.public_key_hex], - # Since the last 3 hours (handles reboots) - "since": int(time.time()) - 3 * 60 * 60, + # Since the last handle_missed_events seconds (handles reboots) + "since": int(time.time()) - self.handle_missed_events, } self.sub.requests_sub_id = self._get_new_subid() # Create responses subscription (needed to track previosly responded requests) res_filter = { "kinds": [23195], "authors": [self.public_key_hex], - "since": int(time.time()) - 3 * 60 * 60, + "since": int(time.time()) - self.handle_missed_events, } self.sub.responses_sub_id = self._get_new_subid() # Subscribe @@ -320,7 +363,6 @@ async def _handle_request(self, event: Dict) -> List[Dict]: # Reference user res["tags"].append(["p", nwc_pubkey]) # Finalize response event - print(res) res["content"] = self._encrypt_content(res["content"], nwc_pubkey) self._sign_event(res) @@ -600,9 +642,17 @@ async def cleanup(self): self.reconnect_task.cancel() except Exception as e: logger.warning("Error closing reconnection task: " + str(e)) + try: + if self.gc_task: + self.gc_task.cancel() + except Exception as e: + logger.warning("Error closing gc loop: " + str(e)) # close the websocket try: if self.ws: await self.ws.close() except Exception as e: logger.warning("Error closing websocket connection: " + str(e)) + + class Config: + arbitrary_types_allowed = True diff --git a/paranoia.py b/paranoia.py new file mode 100644 index 0000000..5ebca7c --- /dev/null +++ b/paranoia.py @@ -0,0 +1,170 @@ +# Run-time hardening to detect unexpected inputs at the edges +from loguru import logger + +ENABLE_HARDENING = True + + +def panic(reason: str): + if not ENABLE_HARDENING: + return + logger.error(f"hardening: {reason}") + raise ValueError(f"hardening: {reason}") + + +# Throw if string contains any non-printable characters +def assert_printable(v: str): + if not ENABLE_HARDENING: + return + if not isinstance(v, str): + panic("not a string " + str(v)) + if not v.isprintable(): + panic("string contains non-printable characters") + + +# Check if number is valid int and not NaN +def assert_valid_int(v: int): + if not ENABLE_HARDENING: + return + if not isinstance(v, int): + panic("number is not a valid int") + + +# Check if number is valid positive int +def assert_valid_positive_int(v: int): + if not ENABLE_HARDENING: + return + assert_valid_int(v) + if v < 0: + panic("number is not positive") + + +# Check if number is a valid sats amount +def assert_valid_sats(v: int): + if not ENABLE_HARDENING: + return + assert_valid_positive_int(v) + max_sats_value = 10_000_000 + if v >= max_sats_value: + panic("sats amount looks too high") + + +# Check if number is a valid msats amount +def assert_valid_msats(v: int): + if not ENABLE_HARDENING: + return + assert_valid_positive_int(v) + max_msats_value = 10_000_000 * 1000 + if v >= max_msats_value: + panic("msats amount looks too high") + + +# Check if string is a valid sha256 hash +def assert_valid_sha256(v: str): + if not ENABLE_HARDENING: + return + assert_printable(v) + if len(v) != 64 or not all(c in "0123456789abcdef" for c in v): + panic("string is not a valid sha256 hash") + + +# Check if value is an hash of an unexpected input (eg. empty strings, booleans etc) +def assert_no_badhash(v: str): + bad_hashes = [ + # empty string + "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + # 1 space string + "36a9e7f1c95b82ffb99743e0c5c4ce95d83c9a430aac59f84ef3cbfab6145068", + # None + "c1c4b7fbd3e146bb14ec6258e5231c1ec703590721ff1e321b179a62b5857c9c", + # True + "cdca0b9bb2325fc8ed7eba7734a3a1f876d919221399b6587ae7d26305adee9d", + # False + "f9e08f8b038b1b401497f17da3adc120667ac742bf035657869a6ca1cd180e69", + ] + if v in bad_hashes: + panic("bad hash detected") + + +# Check if valid nostr pubkey +def assert_valid_pubkey(v: str): + if not ENABLE_HARDENING: + return + assert_valid_sha256(v) + assert_no_badhash(v) + + +# Check if valid wallet id +def assert_valid_wallet_id(v: str): + if not ENABLE_HARDENING: + return + assert_printable(v) + if not v.isalnum(): + panic("string is not a valid wallet id") + + +# Check if valid timestamp in seconds +def assert_valid_timestamp_seconds(v: int): + if not ENABLE_HARDENING: + return + assert_valid_positive_int(v) + if v > 2**31: + panic("timestamp is too high") + + +# Check if valid expiration in seconds +def assert_valid_expiration_seconds(v: int): + if not ENABLE_HARDENING: + return + assert_valid_int(v) + if v == -1: + return + if v < 0: + panic("expiration is invalid") + if v > 2**31: + panic("expiration is too high") + + +# Check if string is within sane parameters +def assert_sane_string(v: str): + if not ENABLE_HARDENING: + return + assert_printable(v) + if len(v) > 1024: + panic("string is too long") + + +# Check if string is a non-empty string +def assert_non_empty_string(v: str): + if not ENABLE_HARDENING: + return + assert_printable(v) + if len(v.strip()) == 0: + panic("string is empty") + + +# Assert valid json +def assert_valid_json(v: str): + if not ENABLE_HARDENING: + return + assert_non_empty_string(v) + try: + import json + + json.loads(v) + except Exception as e: + panic("string is not valid json " + str(e)) + + +# Check if string is a valid bolt11 invoice +def assert_valid_bolt11(invoice: str): + if not ENABLE_HARDENING: + return + assert_printable(invoice) + + +# Check if boolean +def assert_boolean(v: bool): + if not ENABLE_HARDENING: + return + if not isinstance(v, bool): + panic("not a boolean") diff --git a/poetry.lock b/poetry.lock index 46b723f..f25ce14 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,14 +1,32 @@ -# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. + +[[package]] +name = "aiosqlite" +version = "0.20.0" +description = "asyncio bridge to the standard sqlite3 module" +optional = false +python-versions = ">=3.8" +files = [ + {file = "aiosqlite-0.20.0-py3-none-any.whl", hash = "sha256:36a1deaca0cac40ebe32aac9977a6e2bbc7f5189f23f4a54d5908986729e5bd6"}, + {file = "aiosqlite-0.20.0.tar.gz", hash = "sha256:6d35c8c256637f4672f843c31021464090805bf925385ac39473fb16eaaca3d7"}, +] + +[package.dependencies] +typing_extensions = ">=4.0" + +[package.extras] +dev = ["attribution (==1.7.0)", "black (==24.2.0)", "coverage[toml] (==7.4.1)", "flake8 (==7.0.0)", "flake8-bugbear (==24.2.6)", "flit (==3.9.0)", "mypy (==1.8.0)", "ufmt (==2.3.0)", "usort (==1.0.8.post1)"] +docs = ["sphinx (==7.2.6)", "sphinx-mdinclude (==0.5.3)"] [[package]] name = "anyio" -version = "4.4.0" +version = "4.6.2.post1" description = "High level compatibility layer for multiple asynchronous event loop implementations" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "anyio-4.4.0-py3-none-any.whl", hash = "sha256:c1b2d8f46a8a812513012e1107cb0e68c17159a7a594208005a57dc776e1bdc7"}, - {file = "anyio-4.4.0.tar.gz", hash = "sha256:5aadc6a1bbb7cdb0bede386cac5e2940f5e2ff3aa20277e991cf028e0585ce94"}, + {file = "anyio-4.6.2.post1-py3-none-any.whl", hash = "sha256:6d170c36fba3bdd840c73d3868c1e777e33676a69c3a72cf0a0d5d6d8009b61d"}, + {file = "anyio-4.6.2.post1.tar.gz", hash = "sha256:4c8bc31ccdb51c7f7bd251f51c609e038d63e34219b44aa86e47576389880b4c"}, ] [package.dependencies] @@ -18,9 +36,9 @@ sniffio = ">=1.1" typing-extensions = {version = ">=4.1", markers = "python_version < \"3.11\""} [package.extras] -doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] -test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"] -trio = ["trio (>=0.23)"] +doc = ["Sphinx (>=7.4,<8.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] +test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "truststore (>=0.9.1)", "uvloop (>=0.21.0b1)"] +trio = ["trio (>=0.26.1)"] [[package]] name = "asn1crypto" @@ -34,23 +52,72 @@ files = [ ] [[package]] -name = "attrs" -version = "23.2.0" -description = "Classes Without Boilerplate" +name = "async-timeout" +version = "5.0.1" +description = "Timeout context manager for asyncio programs" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "attrs-23.2.0-py3-none-any.whl", hash = "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1"}, - {file = "attrs-23.2.0.tar.gz", hash = "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30"}, + {file = "async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c"}, + {file = "async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3"}, ] +[[package]] +name = "asyncpg" +version = "0.29.0" +description = "An asyncio PostgreSQL driver" +optional = false +python-versions = ">=3.8.0" +files = [ + {file = "asyncpg-0.29.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72fd0ef9f00aeed37179c62282a3d14262dbbafb74ec0ba16e1b1864d8a12169"}, + {file = "asyncpg-0.29.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:52e8f8f9ff6e21f9b39ca9f8e3e33a5fcdceaf5667a8c5c32bee158e313be385"}, + {file = "asyncpg-0.29.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9e6823a7012be8b68301342ba33b4740e5a166f6bbda0aee32bc01638491a22"}, + {file = "asyncpg-0.29.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:746e80d83ad5d5464cfbf94315eb6744222ab00aa4e522b704322fb182b83610"}, + {file = "asyncpg-0.29.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ff8e8109cd6a46ff852a5e6bab8b0a047d7ea42fcb7ca5ae6eaae97d8eacf397"}, + {file = "asyncpg-0.29.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:97eb024685b1d7e72b1972863de527c11ff87960837919dac6e34754768098eb"}, + {file = "asyncpg-0.29.0-cp310-cp310-win32.whl", hash = "sha256:5bbb7f2cafd8d1fa3e65431833de2642f4b2124be61a449fa064e1a08d27e449"}, + {file = "asyncpg-0.29.0-cp310-cp310-win_amd64.whl", hash = "sha256:76c3ac6530904838a4b650b2880f8e7af938ee049e769ec2fba7cd66469d7772"}, + {file = "asyncpg-0.29.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d4900ee08e85af01adb207519bb4e14b1cae8fd21e0ccf80fac6aa60b6da37b4"}, + {file = "asyncpg-0.29.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a65c1dcd820d5aea7c7d82a3fdcb70e096f8f70d1a8bf93eb458e49bfad036ac"}, + {file = "asyncpg-0.29.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b52e46f165585fd6af4863f268566668407c76b2c72d366bb8b522fa66f1870"}, + {file = "asyncpg-0.29.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc600ee8ef3dd38b8d67421359779f8ccec30b463e7aec7ed481c8346decf99f"}, + {file = "asyncpg-0.29.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:039a261af4f38f949095e1e780bae84a25ffe3e370175193174eb08d3cecab23"}, + {file = "asyncpg-0.29.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6feaf2d8f9138d190e5ec4390c1715c3e87b37715cd69b2c3dfca616134efd2b"}, + {file = "asyncpg-0.29.0-cp311-cp311-win32.whl", hash = "sha256:1e186427c88225ef730555f5fdda6c1812daa884064bfe6bc462fd3a71c4b675"}, + {file = "asyncpg-0.29.0-cp311-cp311-win_amd64.whl", hash = "sha256:cfe73ffae35f518cfd6e4e5f5abb2618ceb5ef02a2365ce64f132601000587d3"}, + {file = "asyncpg-0.29.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6011b0dc29886ab424dc042bf9eeb507670a3b40aece3439944006aafe023178"}, + {file = "asyncpg-0.29.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b544ffc66b039d5ec5a7454667f855f7fec08e0dfaf5a5490dfafbb7abbd2cfb"}, + {file = "asyncpg-0.29.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d84156d5fb530b06c493f9e7635aa18f518fa1d1395ef240d211cb563c4e2364"}, + {file = "asyncpg-0.29.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:54858bc25b49d1114178d65a88e48ad50cb2b6f3e475caa0f0c092d5f527c106"}, + {file = "asyncpg-0.29.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:bde17a1861cf10d5afce80a36fca736a86769ab3579532c03e45f83ba8a09c59"}, + {file = "asyncpg-0.29.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:37a2ec1b9ff88d8773d3eb6d3784dc7e3fee7756a5317b67f923172a4748a175"}, + {file = "asyncpg-0.29.0-cp312-cp312-win32.whl", hash = "sha256:bb1292d9fad43112a85e98ecdc2e051602bce97c199920586be83254d9dafc02"}, + {file = "asyncpg-0.29.0-cp312-cp312-win_amd64.whl", hash = "sha256:2245be8ec5047a605e0b454c894e54bf2ec787ac04b1cb7e0d3c67aa1e32f0fe"}, + {file = "asyncpg-0.29.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0009a300cae37b8c525e5b449233d59cd9868fd35431abc470a3e364d2b85cb9"}, + {file = "asyncpg-0.29.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5cad1324dbb33f3ca0cd2074d5114354ed3be2b94d48ddfd88af75ebda7c43cc"}, + {file = "asyncpg-0.29.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:012d01df61e009015944ac7543d6ee30c2dc1eb2f6b10b62a3f598beb6531548"}, + {file = "asyncpg-0.29.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:000c996c53c04770798053e1730d34e30cb645ad95a63265aec82da9093d88e7"}, + {file = "asyncpg-0.29.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:e0bfe9c4d3429706cf70d3249089de14d6a01192d617e9093a8e941fea8ee775"}, + {file = "asyncpg-0.29.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:642a36eb41b6313ffa328e8a5c5c2b5bea6ee138546c9c3cf1bffaad8ee36dd9"}, + {file = "asyncpg-0.29.0-cp38-cp38-win32.whl", hash = "sha256:a921372bbd0aa3a5822dd0409da61b4cd50df89ae85150149f8c119f23e8c408"}, + {file = "asyncpg-0.29.0-cp38-cp38-win_amd64.whl", hash = "sha256:103aad2b92d1506700cbf51cd8bb5441e7e72e87a7b3a2ca4e32c840f051a6a3"}, + {file = "asyncpg-0.29.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5340dd515d7e52f4c11ada32171d87c05570479dc01dc66d03ee3e150fb695da"}, + {file = "asyncpg-0.29.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e17b52c6cf83e170d3d865571ba574577ab8e533e7361a2b8ce6157d02c665d3"}, + {file = "asyncpg-0.29.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f100d23f273555f4b19b74a96840aa27b85e99ba4b1f18d4ebff0734e78dc090"}, + {file = "asyncpg-0.29.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:48e7c58b516057126b363cec8ca02b804644fd012ef8e6c7e23386b7d5e6ce83"}, + {file = "asyncpg-0.29.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f9ea3f24eb4c49a615573724d88a48bd1b7821c890c2effe04f05382ed9e8810"}, + {file = "asyncpg-0.29.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8d36c7f14a22ec9e928f15f92a48207546ffe68bc412f3be718eedccdf10dc5c"}, + {file = "asyncpg-0.29.0-cp39-cp39-win32.whl", hash = "sha256:797ab8123ebaed304a1fad4d7576d5376c3a006a4100380fb9d517f0b59c1ab2"}, + {file = "asyncpg-0.29.0-cp39-cp39-win_amd64.whl", hash = "sha256:cce08a178858b426ae1aa8409b5cc171def45d4293626e7aa6510696d46decd8"}, + {file = "asyncpg-0.29.0.tar.gz", hash = "sha256:d1c49e1f44fffafd9a55e1a9b101590859d881d639ea2922516f5d9c512d354e"}, +] + +[package.dependencies] +async-timeout = {version = ">=4.0.3", markers = "python_version < \"3.12.0\""} + [package.extras] -cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] -dev = ["attrs[tests]", "pre-commit"] -docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"] -tests = ["attrs[tests-no-zope]", "zope-interface"] -tests-mypy = ["mypy (>=1.6)", "pytest-mypy-plugins"] -tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist[psutil]"] +docs = ["Sphinx (>=5.3.0,<5.4.0)", "sphinx-rtd-theme (>=1.2.2)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)"] +test = ["flake8 (>=6.1,<7.0)", "uvloop (>=0.15.3)"] [[package]] name = "base58" @@ -119,133 +186,148 @@ files = [ [[package]] name = "bitarray" -version = "2.9.2" +version = "2.9.3" description = "efficient arrays of booleans -- C extension" optional = false python-versions = "*" files = [ - {file = "bitarray-2.9.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:917905de565d9576eb20f53c797c15ba88b9f4f19728acabec8d01eee1d3756a"}, - {file = "bitarray-2.9.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b35bfcb08b7693ab4bf9059111a6e9f14e07d57ac93cd967c420db58ab9b71e1"}, - {file = "bitarray-2.9.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ea1923d2e7880f9e1959e035da661767b5a2e16a45dfd57d6aa831e8b65ee1bf"}, - {file = "bitarray-2.9.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e0b63a565e8a311cc8348ff1262d5784df0f79d64031d546411afd5dd7ef67d"}, - {file = "bitarray-2.9.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cf0620da2b81946d28c0b16f3e3704d38e9837d85ee4f0652816e2609aaa4fed"}, - {file = "bitarray-2.9.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:79a9b8b05f2876c7195a2b698c47528e86a73c61ea203394ff8e7a4434bda5c8"}, - {file = "bitarray-2.9.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:345c76b349ff145549652436235c5532e5bfe9db690db6f0a6ad301c62b9ef21"}, - {file = "bitarray-2.9.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4e2936f090bf3f4d1771f44f9077ebccdbc0415d2b598d51a969afcb519df505"}, - {file = "bitarray-2.9.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:f9346e98fc2abcef90b942973087e2462af6d3e3710e82938078d3493f7fef52"}, - {file = "bitarray-2.9.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e6ec283d4741befb86e8c3ea2e9ac1d17416c956d392107e45263e736954b1f7"}, - {file = "bitarray-2.9.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:962892646599529917ef26266091e4cb3077c88b93c3833a909d68dcc971c4e3"}, - {file = "bitarray-2.9.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:e8da5355d7d75a52df5b84750989e34e39919ec7e59fafc4c104cc1607ab2d31"}, - {file = "bitarray-2.9.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:603e7d640e54ad764d2b4da6b61e126259af84f253a20f512dd10689566e5478"}, - {file = "bitarray-2.9.2-cp310-cp310-win32.whl", hash = "sha256:f00079f8e69d75c2a417de7961a77612bb77ef46c09bc74607d86de4740771ef"}, - {file = "bitarray-2.9.2-cp310-cp310-win_amd64.whl", hash = "sha256:1bb33673e7f7190a65f0a940c1ef63266abdb391f4a3e544a47542d40a81f536"}, - {file = "bitarray-2.9.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:fe71fd4b76380c2772f96f1e53a524da7063645d647a4fcd3b651bdd80ca0f2e"}, - {file = "bitarray-2.9.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d527172919cdea1e13994a66d9708a80c3d33dedcf2f0548e4925e600fef3a3a"}, - {file = "bitarray-2.9.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:052c5073bdcaa9dd10628d99d37a2f33ec09364b86dd1f6281e2d9f8d3db3060"}, - {file = "bitarray-2.9.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e064caa55a6ed493aca1eda06f8b3f689778bc780a75e6ad7724642ba5dc62f7"}, - {file = "bitarray-2.9.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:508069a04f658210fdeee85a7a0ca84db4bcc110cbb1d21f692caa13210f24a7"}, - {file = "bitarray-2.9.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4da73ebd537d75fa7bccfc2228fcaedea0803f21dd9d0bf0d3b67fef3c4af294"}, - {file = "bitarray-2.9.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5cb378eaa65cd43098f11ff5d27e48ee3b956d2c00d2d6b5bfc2a09fe183be47"}, - {file = "bitarray-2.9.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d14c790b91f6cbcd9b718f88ed737c78939980c69ac8c7f03dd7e60040c12951"}, - {file = "bitarray-2.9.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:7eea9318293bc0ea6447e9ebfba600a62f3428bea7e9c6d42170ae4f481dbab3"}, - {file = "bitarray-2.9.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:b76ffec27c7450b8a334f967366a9ebadaea66ee43f5b530c12861b1a991f503"}, - {file = "bitarray-2.9.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:76b76a07d4ee611405045c6950a1e24c4362b6b44808d4ad6eea75e0dbc59af4"}, - {file = "bitarray-2.9.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:c7d16beeaaab15b075990cd26963d6b5b22e8c5becd131781514a00b8bdd04bd"}, - {file = "bitarray-2.9.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:60df43e868a615c7e15117a1e1c2e5e11f48f6457280eba6ddf8fbefbec7da99"}, - {file = "bitarray-2.9.2-cp311-cp311-win32.whl", hash = "sha256:e788608ed7767b7b3bbde6d49058bccdf94df0de9ca75d13aa99020cc7e68095"}, - {file = "bitarray-2.9.2-cp311-cp311-win_amd64.whl", hash = "sha256:a23397da092ef0a8cfe729571da64c2fc30ac18243caa82ac7c4f965087506ff"}, - {file = "bitarray-2.9.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:90e3a281ffe3897991091b7c46fca38c2675bfd4399ffe79dfeded6c52715436"}, - {file = "bitarray-2.9.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:bed637b674db5e6c8a97a4a321e3e4d73e72d50b5c6b29950008a93069cc64cd"}, - {file = "bitarray-2.9.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e49066d251dbbe4e6e3a5c3937d85b589e40e2669ad0eef41a00f82ec17d844b"}, - {file = "bitarray-2.9.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c4344e96642e2211fb3a50558feff682c31563a4c64529a931769d40832ca79"}, - {file = "bitarray-2.9.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aeb60962ec4813c539a59fbd4f383509c7222b62c3fb1faa76b54943a613e33a"}, - {file = "bitarray-2.9.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ed0f7982f10581bb16553719e5e8f933e003f5b22f7d25a68bdb30fac630a6ff"}, - {file = "bitarray-2.9.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c71d1cabdeee0cdda4669168618f0e46b7dace207b29da7b63aaa1adc2b54081"}, - {file = "bitarray-2.9.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b0ef2d0a6f1502d38d911d25609b44c6cc27bee0a4363dd295df78b075041b60"}, - {file = "bitarray-2.9.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:6f71d92f533770fb027388b35b6e11988ab89242b883f48a6fe7202d238c61f8"}, - {file = "bitarray-2.9.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:ba0734aa300757c924f3faf8148e1b8c247176a0ac8e16aefdf9c1eb19e868f7"}, - {file = "bitarray-2.9.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:d91406f413ccbf4af6ab5ae7bc78f772a95609f9ddd14123db36ef8c37116d95"}, - {file = "bitarray-2.9.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:87abb7f80c0a042f3fe8e5264da1a2756267450bb602110d5327b8eaff7682e7"}, - {file = "bitarray-2.9.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4b558ce85579b51a2e38703877d1e93b7728a7af664dd45a34e833534f0b755d"}, - {file = "bitarray-2.9.2-cp312-cp312-win32.whl", hash = "sha256:dac2399ee2889fbdd3472bfc2ede74c34cceb1ccf29a339964281a16eb1d3188"}, - {file = "bitarray-2.9.2-cp312-cp312-win_amd64.whl", hash = "sha256:48a30d718d1a6dfc22a49547450107abe8f4afdf2abdcbe76eb9ed88edc49498"}, - {file = "bitarray-2.9.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:2c6be1b651fad8f3adb7a5aa12c65b612cd9b89530969af941844ae680f7d981"}, - {file = "bitarray-2.9.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5b399ae6ab975257ec359f03b48fc00b1c1cd109471e41903548469b8feae5c"}, - {file = "bitarray-2.9.2-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0b3543c8a1cb286ad105f11c25d8d0f712f41c5c55f90be39f0e5a1376c7d0b0"}, - {file = "bitarray-2.9.2-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:03adaacb79e2fb8f483ab3a67665eec53bb3fd0cd5dbd7358741aef124688db3"}, - {file = "bitarray-2.9.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ae5b0657380d2581e13e46864d147a52c1e2bbac9f59b59c576e42fa7d10cf0"}, - {file = "bitarray-2.9.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7c1f4bf6ea8eb9d7f30808c2e9894237a96650adfecbf5f3643862dc5982f89e"}, - {file = "bitarray-2.9.2-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:a8873089be2aa15494c0f81af1209f6e1237d762c5065bc4766c1b84321e1b50"}, - {file = "bitarray-2.9.2-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:677e67f50e2559efc677a4366707070933ad5418b8347a603a49a070890b19bc"}, - {file = "bitarray-2.9.2-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:a620d8ce4ea2f1c73c6b6b1399e14cb68c6915e2be3fad5808c2998ed55b4acf"}, - {file = "bitarray-2.9.2-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:64115ccabbdbe279c24c367b629c6b1d3da9ed36c7420129e27c338a3971bfee"}, - {file = "bitarray-2.9.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:5d6fb422772e75385b76ad1c52f45a68bd4efafd8be8d0061c11877be74c4d43"}, - {file = "bitarray-2.9.2-cp36-cp36m-win32.whl", hash = "sha256:852e202875dd6dfd6139ce7ec4e98dac2b17d8d25934dc99900831e81c3adaef"}, - {file = "bitarray-2.9.2-cp36-cp36m-win_amd64.whl", hash = "sha256:7dfefdcb0dc6a3ba9936063cec65a74595571b375beabe18742b3d91d087eefd"}, - {file = "bitarray-2.9.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b306c4cf66912511422060f7f5e1149c8bdb404f8e00e600561b0749fdd45659"}, - {file = "bitarray-2.9.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a09c4f81635408e3387348f415521d4b94198c562c23330f560596a6aaa26eaf"}, - {file = "bitarray-2.9.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5361413fd2ecfdf44dc8f065177dc6aba97fa80a91b815586cb388763acf7f8d"}, - {file = "bitarray-2.9.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e8a9475d415ef1eaae7942df6f780fa4dcd48fce32825eda591a17abba869299"}, - {file = "bitarray-2.9.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9b87baa7bfff9a5878fcc1bffe49ecde6e647a72a64b39a69cd8a2992a43a34"}, - {file = "bitarray-2.9.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bb6b86cfdfc503e92cb71c68766a24565359136961642504a7cc9faf936d9c88"}, - {file = "bitarray-2.9.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:cd56b8ae87ebc71bcacbd73615098e8a8de952ecbb5785b6b4e2b07da8a06e1f"}, - {file = "bitarray-2.9.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:3fa909cfd675004aed8b4cc9df352415933656e0155a6209d878b7cb615c787e"}, - {file = "bitarray-2.9.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:b069ca9bf728e0c5c5b60e00a89df9af34cc170c695c3bfa3b372d8f40288efb"}, - {file = "bitarray-2.9.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:6067f2f07a7121749858c7daa93c8774325c91590b3e81a299621e347740c2ae"}, - {file = "bitarray-2.9.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:321841cdad1dd0f58fe62e80e9c9c7531f8ebf8be93f047401e930dc47425b1e"}, - {file = "bitarray-2.9.2-cp37-cp37m-win32.whl", hash = "sha256:54e16e32e60973bb83c315de9975bc1bcfc9bd50bb13001c31da159bc49b0ca1"}, - {file = "bitarray-2.9.2-cp37-cp37m-win_amd64.whl", hash = "sha256:f4dcadb7b8034aa3491ee8f5a69b3d9ba9d7d1e55c3cc1fc45be313e708277f8"}, - {file = "bitarray-2.9.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:c8919fdbd3bb596b104388b56ae4b266eb28da1f2f7dff2e1f9334a21840fe96"}, - {file = "bitarray-2.9.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:eb7a9d8a2e400a1026de341ad48e21670a6261a75b06df162c5c39b0d0e7c8f4"}, - {file = "bitarray-2.9.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6ec84668dd7b937874a2b2c293cd14ba84f37be0d196dead852e0ada9815d807"}, - {file = "bitarray-2.9.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2de9a31c34e543ae089fd2a5ced01292f725190e379921384f695e2d7184bd3"}, - {file = "bitarray-2.9.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9521f49ae121a17c0a41e5112249e6fa7f6a571245b1118de81fb86e7c1bc1ce"}, - {file = "bitarray-2.9.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6cc6545d6d76542aee3d18c1c9485fb7b9812b8df4ebe52c4535ec42081b48f"}, - {file = "bitarray-2.9.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:856bbe1616425f71c0df5ef2e8755e878d9504d5a531acba58ab4273c52c117a"}, - {file = "bitarray-2.9.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d4bba8042ea6ab331ade91bc435d81ad72fddb098e49108610b0ce7780c14e68"}, - {file = "bitarray-2.9.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a035da89c959d98afc813e3c62f052690d67cfd55a36592f25d734b70de7d4b0"}, - {file = "bitarray-2.9.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:6d70b1579da7fb71be5a841a1f965d19aca0ef27f629cfc07d06b09aafd0a333"}, - {file = "bitarray-2.9.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:405b83bed28efaae6d86b6ab287c75712ead0adbfab2a1075a1b7ab47dad4d62"}, - {file = "bitarray-2.9.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:7eb8be687c50da0b397d5e0ab7ca200b5ebb639e79a9f5e285851d1944c94be9"}, - {file = "bitarray-2.9.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:eceb551dfeaf19c609003a69a0cf8264b0efd7abc3791a11dfabf4788daf0d19"}, - {file = "bitarray-2.9.2-cp38-cp38-win32.whl", hash = "sha256:bb198c6ed1edbcdaf3d1fa3c9c9d1cdb7e179a5134ef5ee660b53cdec43b34e7"}, - {file = "bitarray-2.9.2-cp38-cp38-win_amd64.whl", hash = "sha256:648d2f2685590b0103c67a937c2fb9e09bcc8dfb166f0c7c77bd341902a6f5b3"}, - {file = "bitarray-2.9.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:ea816dc8f8e65841a8bbdd30e921edffeeb6f76efe6a1eb0da147b60d539d1cf"}, - {file = "bitarray-2.9.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4d0e32530f941c41eddfc77600ec89b65184cb909c549336463a738fab3ed285"}, - {file = "bitarray-2.9.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4a22266fb416a3b6c258bf7f83c9fe531ba0b755a56986a81ad69dc0f3bcc070"}, - {file = "bitarray-2.9.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc6d3e80dd8239850f2604833ff3168b28909c8a9357abfed95632cccd17e3e7"}, - {file = "bitarray-2.9.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f135e804986b12bf14f2cd1eb86674c47dea86c4c5f0fa13c88978876b97ebe6"}, - {file = "bitarray-2.9.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87580c7f7d14f7ec401eda7adac1e2a25e95153e9c339872c8ae61b3208819a1"}, - {file = "bitarray-2.9.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64b433e26993127732ac7b66a7821b2537c3044355798de7c5fcb0af34b8296f"}, - {file = "bitarray-2.9.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e497c535f2a9b68c69d36631bf2dba243e05eb343b00b9c7bbdc8c601c6802d"}, - {file = "bitarray-2.9.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:e40b3cb9fa1edb4e0175d7c06345c49c7925fe93e39ef55ecb0bc40c906b0c09"}, - {file = "bitarray-2.9.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f2f8692f95c9e377eb19ca519d30d1f884b02feb7e115f798de47570a359e43f"}, - {file = "bitarray-2.9.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:f0b84fc50b6dbeced4fa390688c07c10a73222810fb0e08392bd1a1b8259de36"}, - {file = "bitarray-2.9.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:d656ad38c942e38a470ddbce26b5020e08e1a7ea86b8fd413bb9024b5189993a"}, - {file = "bitarray-2.9.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6ab0f1dbfe5070db98771a56aa14797595acd45a1af9eadfb193851a270e7996"}, - {file = "bitarray-2.9.2-cp39-cp39-win32.whl", hash = "sha256:0a99b23ac845a9ea3157782c97465e6ae026fe0c7c4c1ed1d88f759fd6ea52d9"}, - {file = "bitarray-2.9.2-cp39-cp39-win_amd64.whl", hash = "sha256:9bbcfc7c279e8d74b076e514e669b683f77b4a2a328585b3f16d4c5259c91222"}, - {file = "bitarray-2.9.2-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:43847799461d8ba71deb4d97b47250c2c2fb66d82cd3cb8b4caf52bb97c03034"}, - {file = "bitarray-2.9.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4f44381b0a4bdf64416082f4f0e7140377ae962c0ced6f983c6d7bbfc034040"}, - {file = "bitarray-2.9.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a484061616fb4b158b80789bd3cb511f399d2116525a8b29b6334c68abc2310f"}, - {file = "bitarray-2.9.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1ff9e38356cc803e06134cf8ae9758e836ccd1b793135ef3db53c7c5d71e93bc"}, - {file = "bitarray-2.9.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:b44105792fbdcfbda3e26ee88786790fda409da4c71f6c2b73888108cf8f062f"}, - {file = "bitarray-2.9.2-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:7e913098de169c7fc890638ce5e171387363eb812579e637c44261460ac00aa2"}, - {file = "bitarray-2.9.2-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6fe315355cdfe3ed22ef355b8bdc81a805ca4d0949d921576560e5b227a1112"}, - {file = "bitarray-2.9.2-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f708e91fdbe443f3bec2df394ed42328fb9b0446dff5cb4199023ac6499e09fd"}, - {file = "bitarray-2.9.2-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5b7b09489b71f9f1f64c0fa0977e250ec24500767dab7383ba9912495849cadf"}, - {file = "bitarray-2.9.2-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:128cc3488176145b9b137fdcf54c1c201809bbb8dd30b260ee40afe915843b43"}, - {file = "bitarray-2.9.2-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:21f21e7f56206be346bdbda2a6bdb2165a5e6a11821f88fd4911c5a6bbbdc7e2"}, - {file = "bitarray-2.9.2-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f4dd3af86dd8a617eb6464622fb64ca86e61ce99b59b5c35d8cd33f9c30603d"}, - {file = "bitarray-2.9.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6465de861aff7a2559f226b37982007417eab8c3557543879987f58b453519bd"}, - {file = "bitarray-2.9.2-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbaf2bb71d6027152d603f1d5f31e0dfd5e50173d06f877bec484e5396d4594b"}, - {file = "bitarray-2.9.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:2f32948c86e0d230a296686db28191b67ed229756f84728847daa0c7ab7406e3"}, - {file = "bitarray-2.9.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:be94e5a685e60f9d24532af8fe5c268002e9016fa80272a94727f435de3d1003"}, - {file = "bitarray-2.9.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5cc9381fd54f3c23ae1039f977bfd6d041a5c3c1518104f616643c3a5a73b15"}, - {file = "bitarray-2.9.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cd926e8ae4d1ed1ac4a8f37212a62886292f692bc1739fde98013bf210c2d175"}, - {file = "bitarray-2.9.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:461a3dafb9d5fda0bb3385dc507d78b1984b49da3fe4c6d56c869a54373b7008"}, - {file = "bitarray-2.9.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:393cb27fd859af5fd9c16eb26b1c59b17b390ff66b3ae5d0dd258270191baf13"}, - {file = "bitarray-2.9.2.tar.gz", hash = "sha256:a8f286a51a32323715d77755ed959f94bef13972e9a2fe71b609e40e6d27957e"}, + {file = "bitarray-2.9.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2cf5f5400636c7dda797fd681795ce63932458620fe8c40955890380acba9f62"}, + {file = "bitarray-2.9.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3487b4718ffa5942fab777835ee36085f8dda7ec4bd0b28433efb117f84852b6"}, + {file = "bitarray-2.9.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:10f44b1e4994035408bea54d7bf0aec79744cad709706bedf28091a48bb7f1a4"}, + {file = "bitarray-2.9.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb5c16f97c65add6535748a9c98c70e7ca79759c38a2eb990127fef72f76111a"}, + {file = "bitarray-2.9.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:13dbfc42971ba84e9c4ba070f720df6570285a3f89187f07ef422efcb611c19f"}, + {file = "bitarray-2.9.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c28076acfbe7f9a5494d7ae98094a6e209c390c340938845f294818ebf5e4d3"}, + {file = "bitarray-2.9.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b7cdd21835936d9a66477836ca23b2cb63295142cb9d9158883e2c0f1f8f6bd"}, + {file = "bitarray-2.9.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9f60887ab3a46e507fa6f8544d8d4b0748da48718591dfe3fe80c62bdea60f10"}, + {file = "bitarray-2.9.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f75e1abd4a37cba3002521d3f5e2b50ef4f4a74342207cad3f52468411d5d8ba"}, + {file = "bitarray-2.9.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:dc63da9695383c048b83f5ab77eab35a55bbb2e77c7b6e762eba219929b45b84"}, + {file = "bitarray-2.9.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:6fe5a57b859d9bc9c2fd27c78c4b7b83158faf984202de6fb44618caeebfff10"}, + {file = "bitarray-2.9.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:1fe5a37bd9441a5ecc2f6e71b43df7176fa376a542ef97484310b8b46a45649a"}, + {file = "bitarray-2.9.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8a16e42c169ca818d6a15b5dd5acd5d2a26af0fa0588e1036e0e58d01f8387d4"}, + {file = "bitarray-2.9.3-cp310-cp310-win32.whl", hash = "sha256:5e6b5e7940af3474ffaa930cd1ce8215181cbe864d6b5ddb67a15d3c15e935cd"}, + {file = "bitarray-2.9.3-cp310-cp310-win_amd64.whl", hash = "sha256:c63dbb99ef2ab1281871678624f9c9a5f1682b826e668ce559275ec488b3fa8b"}, + {file = "bitarray-2.9.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:49fb93b488d180f5c84b79fe687c585a84bf0295ff035d63e09ee24ce1da0558"}, + {file = "bitarray-2.9.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c2944fb83bbc2aa7f29a713bc4f8c1318e54fa0d06a72bedd350a3fb4a4b91d8"}, + {file = "bitarray-2.9.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3612d9d3788dc62f1922c917b1539f1cdf02cecc9faef8ae213a8b36093136ca"}, + {file = "bitarray-2.9.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:90a9300cdb7c99b1e692bb790cba8acecee1a345a83e58e28c94a0d87c522237"}, + {file = "bitarray-2.9.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1211ed66acbbb221fd7554abf4206a384d79e6192d5cb95325c5c361bbb52a74"}, + {file = "bitarray-2.9.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:67757279386accf93eba76b8f97b5acf1664a3e350cbea5f300f53490f8764fd"}, + {file = "bitarray-2.9.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64e19c6a99c32f460c2613f797f77aa37d8e298891d00ea5355158cce80e11ec"}, + {file = "bitarray-2.9.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:72734bd3775f43c5a75385730abb9f84fee6c627eb14f579de4be478f1615c8c"}, + {file = "bitarray-2.9.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a92703471b5d3316c7481bc1852f620f42f7a1b62be27f39d13694827635786f"}, + {file = "bitarray-2.9.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:d5d77c81300ca430d4b195ccfbb629d6858258f541b6e96c6b11ec1563cd2681"}, + {file = "bitarray-2.9.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:3ba8a29c0d091c952ced1607ce715f5e0524899f24333a493807d00f5938463d"}, + {file = "bitarray-2.9.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:418171d035b191dbe5e86cd2bfb5c3e1ae7d947edc22857a897d1c7251674ae5"}, + {file = "bitarray-2.9.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1e0bd272eba256183be2a17488f9cb096d2e6d3435ecf2e28c1e0857c6d20749"}, + {file = "bitarray-2.9.3-cp311-cp311-win32.whl", hash = "sha256:cc3fd2b0637a619cf13e122bbcf4729ae214d5f25623675597e67c25f9edfe61"}, + {file = "bitarray-2.9.3-cp311-cp311-win_amd64.whl", hash = "sha256:e1fc2a81a585dbe5e367682156e6350d908a56e2ffd6ca651b0af01994db596f"}, + {file = "bitarray-2.9.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:dc47be026f76f1728af00dc7140cec8483fe2f0c476bbf2a59ef47865e00ff96"}, + {file = "bitarray-2.9.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:82b091742ff511cdb06f90af0d2c22e7af3dbff9b8212e2e0d88dfef6a8570b3"}, + {file = "bitarray-2.9.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2d5edb4302a0e3a3d1d0eeb891de3c615d4cb7a446fb41c21eecdcfb29400a6f"}, + {file = "bitarray-2.9.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb4786c5525069c19820549dd2f42d33632bc42959ad167138bd8ee5024b922b"}, + {file = "bitarray-2.9.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9bfe2de2b4df61ccb9244871a0fdf1fff83be0c1bd7187048c3cf7f81c5fe631"}, + {file = "bitarray-2.9.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:31e4f69538f95d2934587d957eea0d283162322dd1af29e57122b20b8cd60f92"}, + {file = "bitarray-2.9.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8ca44908b2bc08d8995770018638d62626706864f9c599b7818225a12f3dbc2c"}, + {file = "bitarray-2.9.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:279f8de5d251ee521e365df29c927d9b5732f1ed4f373d2dbbd278fcbad94ff5"}, + {file = "bitarray-2.9.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c49bb631b38431c09ecd534d56ef04264397d24d18c4ee6653c84e14ae09d92d"}, + {file = "bitarray-2.9.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:192bffc93ee9a5b6c833c98d1dcc81f5633ddd726b85e18341387d0c1d51f691"}, + {file = "bitarray-2.9.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c516cec28c6511df51d87033f40ec420324a2247469b0c989d344f4d27ea37d2"}, + {file = "bitarray-2.9.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:66241cb9a1c1db294f46cd440141e57e8242874e38f3f61877f72d92ae14768a"}, + {file = "bitarray-2.9.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ab1f0e7631110c89bea7b605c0c35832333eb9cc97e5de05d71c76d42a1858c9"}, + {file = "bitarray-2.9.3-cp312-cp312-win32.whl", hash = "sha256:42aa5bee6fe8ad3385eaf5c6585016bbc38a7b75efb52ce5c6f8e00e05237dfa"}, + {file = "bitarray-2.9.3-cp312-cp312-win_amd64.whl", hash = "sha256:dc3fd647d845b94fac3652390866f921f914a17f3807a031c826f68dae3f43e3"}, + {file = "bitarray-2.9.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:fcfcc1989e3e021a282624017b7fb754210f5332e933b1c3ebc79643727b6551"}, + {file = "bitarray-2.9.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:71b1e229a706798a9e106ca7b03d4c63455deb40b18c92950ec073a05a8f8285"}, + {file = "bitarray-2.9.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4bb49556d3d505d24c942a4206ad4d0d40e89fa3016a7ea6edc994d5c08d4a8e"}, + {file = "bitarray-2.9.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4466aa1e533a59d5f7fd37219d154ec3f2ba73fce3d8a2e11080ec475bc15fb"}, + {file = "bitarray-2.9.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a9b75adc0fd0bf278bea89dc3d679d74e10d2df98d3d074b7f3d36f323138818"}, + {file = "bitarray-2.9.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:701582bbbeac372b1cd8a3c9daf6c2336dc2d22e14373a6271d788bc4f2b6edc"}, + {file = "bitarray-2.9.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ea1f119668bbdbd68008031491515e84441e505163918819994b28f295f762c"}, + {file = "bitarray-2.9.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9f400bc18a70bfdb073532c3054ecd78a0e64f96ff7b6140adde5b122580ec2b"}, + {file = "bitarray-2.9.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:aacff5656fb3e15cede7d02903da2634d376aa928d7a81ec8df19b0724d7972a"}, + {file = "bitarray-2.9.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:8a2ae42a14cbf766d4478d7101da6359b0648dd813e60eb3486ac56ad2f5add3"}, + {file = "bitarray-2.9.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:616698edb547d10f0b960cb9f2e8629c55a420dd4c2b1ab46706f49a1815621d"}, + {file = "bitarray-2.9.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:f277c50ba184929dfeed39b6cf9468e3446093521b0aeb52bd54a21ca08f5473"}, + {file = "bitarray-2.9.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:661237739b385c90d8837d5e96b06de093cc6e610236977e198f88f5a979686e"}, + {file = "bitarray-2.9.3-cp313-cp313-win32.whl", hash = "sha256:68acec6c19d798051f178a1197b76f891985f683f95a4b12811b68e58b080f5a"}, + {file = "bitarray-2.9.3-cp313-cp313-win_amd64.whl", hash = "sha256:3055720afdcfd7e8f630fa16db7bed7e55c9d0a1f4756195e3b250e203f3b436"}, + {file = "bitarray-2.9.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:72bf17d0e7d8a4f645655a07999d23e42472cbf2100b8dad7ce26586075241d7"}, + {file = "bitarray-2.9.3-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cfd332b5f1ad8c4dc3cc79ecef33c19b42d8d8e6a39fd5c9ecb5855be0b9723"}, + {file = "bitarray-2.9.3-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d5b466ef1e48f25621c9d27e95deb5e33b8656827ed8aa530b972de73870bd1f"}, + {file = "bitarray-2.9.3-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:938cf26fdaf4d0adfac82d830c025523c5d36ddead0470b735286028231c1784"}, + {file = "bitarray-2.9.3-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0f766669e768ef9a2b23ecfa710b38b6a48da3f91755113c79320b207ae255d"}, + {file = "bitarray-2.9.3-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5b6337c0c64044f35ddfb241143244aac707a68f34ae31a71dad115f773ccc8b"}, + {file = "bitarray-2.9.3-cp36-cp36m-musllinux_1_2_aarch64.whl", hash = "sha256:731b59540167f8b2b20f69f487ecee2339fc4657059906a16cb51acac17f89c3"}, + {file = "bitarray-2.9.3-cp36-cp36m-musllinux_1_2_i686.whl", hash = "sha256:4feed0539a9d6432361fc4d3820eea3a81fa631d542f166cf8430aad81a971da"}, + {file = "bitarray-2.9.3-cp36-cp36m-musllinux_1_2_ppc64le.whl", hash = "sha256:eb65c96a42e73f35175ec738d67992ffdf054c20abee3933cfcfa2343fa1187d"}, + {file = "bitarray-2.9.3-cp36-cp36m-musllinux_1_2_s390x.whl", hash = "sha256:4f40ceac94d182de6135759d81289683ff3e4cf0da709bc5826a7fe00d754114"}, + {file = "bitarray-2.9.3-cp36-cp36m-musllinux_1_2_x86_64.whl", hash = "sha256:5b29f7844080a281635a231a37e99f0bd6f567af6cf19f4f6d212137f99a9cdf"}, + {file = "bitarray-2.9.3-cp36-cp36m-win32.whl", hash = "sha256:947cf522a3b339b73114d12417fd848fa01303dbaa7883ced4c87688dba5637c"}, + {file = "bitarray-2.9.3-cp36-cp36m-win_amd64.whl", hash = "sha256:ea794ea60d514d68777a87a74106110db7a4bbc2c46720e67010e3071afefb95"}, + {file = "bitarray-2.9.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c7bc7cb79dcac8bdce23b305e671c06eaeffb012fa065b8c33bc51df7e1733f0"}, + {file = "bitarray-2.9.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6d6380ad0f929ad9220abadd1c9b7234271c4b6ea9c753a88611d489e93a8f2e"}, + {file = "bitarray-2.9.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:05f4e2451e2ad450b41ede8440e52c1fd798e81027e1dc2256292ec0787d3bf1"}, + {file = "bitarray-2.9.3-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7267885c98138f3707c710d5b08eedef150a3e5112c760cfe1200f3366fd7064"}, + {file = "bitarray-2.9.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:976957423cb41df8fe0eb811dbb53d8c5ab1ca3beec7a3ca7ff679be44a72714"}, + {file = "bitarray-2.9.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c0ec5141a69f73ed6ff17ea7344d5cc166e087095bfe3661dbb42b519e76aa16"}, + {file = "bitarray-2.9.3-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:218a1b7c0652a3c1020f903ded0f9768c3719fb6d43a6e9d346e985292992d35"}, + {file = "bitarray-2.9.3-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:cf0c9ebf2df280794244e1e12ed626357506ddaa2f0d6f69efe493ae7bbf4bf7"}, + {file = "bitarray-2.9.3-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:c450a04a7e091b57d4c0bd1531648522cd0ef26913ad0e5dea0432ea29b0e5c1"}, + {file = "bitarray-2.9.3-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:a212eb89a50e32ef4969387e44a7410447dc59587615e3966d090edc338a1b85"}, + {file = "bitarray-2.9.3-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:4269232026212ee6b73379b88a578107a6b36a6182307a49d5509686c7495261"}, + {file = "bitarray-2.9.3-cp37-cp37m-win32.whl", hash = "sha256:8a0fb358e6a43f216c3fb0871e2ac14c16563aec363c23bc2fbbb18f6201285d"}, + {file = "bitarray-2.9.3-cp37-cp37m-win_amd64.whl", hash = "sha256:a8368774cdc737eec8fce6f28d0abc095fbc0edccf8fab8d29fddc264b68def9"}, + {file = "bitarray-2.9.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:7d0724a4fef6ded914075a3385ea2d05afdeed567902f83490ed4e7e7e75d9bf"}, + {file = "bitarray-2.9.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0e11b37c6dff6f41ebc49914628824ceb8c8d6ebd0fda2ebe3c0fe0c63e8621e"}, + {file = "bitarray-2.9.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:085f4081d72c7468f82f722a9f113e03a1f7a4c132ef4c2a4e680c5d78b7db00"}, + {file = "bitarray-2.9.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b530b5fbed2900634fbc43f546e384abd72ad9c49795ff5bd6a93cac1aa9c4d8"}, + {file = "bitarray-2.9.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:09ff88e4385967571146fb0d270442de39393d44198f4d108f3350cfd6486f0b"}, + {file = "bitarray-2.9.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a344bb212ddf87db4976a6711d274660a5d887da4fd3faafcdaa092152f85a6d"}, + {file = "bitarray-2.9.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc569c96b990f92fd5946d5b50501fee48b01a116a286d1de7961ebd9c6f06f3"}, + {file = "bitarray-2.9.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2fbbe7938ef8a7abe3e8519fa0578b51d2787f7171d3144e7d373551b5851fd"}, + {file = "bitarray-2.9.3-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:0b5912fab904507b47217509b01aa903d7f98b6e725e490a7f01661f4d9a4fa7"}, + {file = "bitarray-2.9.3-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:0c836ccfca9cf60927256738ef234dfe500565492eff269610cdd1bca56801d0"}, + {file = "bitarray-2.9.3-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:af0e4441ebf51c18fc450962f1e201c96f444d63b17cc8dcf7c0b05111bd4486"}, + {file = "bitarray-2.9.3-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:9e9b57175fb6fe76d7ddd0647e06a25f6e23f4b54b5febf337c5a840ab37dc3b"}, + {file = "bitarray-2.9.3-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:7f7de81721ae9492926bd067007ac974692182bb83fc8f0ba330a67f37a018bd"}, + {file = "bitarray-2.9.3-cp38-cp38-win32.whl", hash = "sha256:4beafb6b6e344385480df6611fdebfcb3579bbb40636ce1ddf5e72fb744e095f"}, + {file = "bitarray-2.9.3-cp38-cp38-win_amd64.whl", hash = "sha256:d8eaeca98900bd6f06a29cdef57999813a67d314f661d14901d71e04f4cf9f00"}, + {file = "bitarray-2.9.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:413965d9d384aef90e58b959f4a39f1d5060b145c26080297b7b4cf23cf38faa"}, + {file = "bitarray-2.9.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2fbb56f2bb89c3a15304a6c0ea56013dc340a98337d9bbd7fc5c21451dc05f8c"}, + {file = "bitarray-2.9.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b8a84f39f7885627711473872d8fc58fc7a0a1e4ecd9ddf42daf9a3643432742"}, + {file = "bitarray-2.9.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45147a9c8580e857c1344d15bd49d2b4387777bd582a2ede11be2ba740653f28"}, + {file = "bitarray-2.9.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ed255423dc60c6b2d5c0d90c13dea2962a31929767fdf1c525ab3210269e75c5"}, + {file = "bitarray-2.9.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4f5bd02671ea5c4ad52bbfe0e8e8197b6e8fa85dec1e93a4a05448c19354cc65"}, + {file = "bitarray-2.9.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1c99c58f044549c93fb6d4cda22678deccaed19845eaa2e6917b5b7ca058f2d"}, + {file = "bitarray-2.9.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:921ee87681e32e17d1849e11c96eb6a8a7edaa1269dd26831013daf8546bde05"}, + {file = "bitarray-2.9.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2ed97d8ec40c4658d9f9aa8f26cb473f44fa1dbccba3fa3fbe4a102e38c6a8d7"}, + {file = "bitarray-2.9.3-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:9d7f7db37edb9c50c9aad6a18f2e87dd7dc5ff2a33406821804a03263fedb2ca"}, + {file = "bitarray-2.9.3-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:292f726cdb9efc744ed0a1d7453c44151526648148a28d9a2495cc7c7b2c62a8"}, + {file = "bitarray-2.9.3-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:2cc94784238782a9376f307b1aa9a85ce77b6eded9f82d2fe062db7fdb02c645"}, + {file = "bitarray-2.9.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:5051436b1d318f6ce0df3b2f8a60bfa66a54c1d9e8719d6cb6b448140e7061f2"}, + {file = "bitarray-2.9.3-cp39-cp39-win32.whl", hash = "sha256:a3d436c686ce59fd0b93438ed2c0e1d3e1716e56bce64b874d05b9f49f1ca5d1"}, + {file = "bitarray-2.9.3-cp39-cp39-win_amd64.whl", hash = "sha256:f168fc45664266a560f2cb28a327041b7f69d4a7faad8ab89e0a1dd7c270a70d"}, + {file = "bitarray-2.9.3-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ae36787299cff41f212aee33cfe1defee13979a41552665a412b6ca3fa8f7eb8"}, + {file = "bitarray-2.9.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42afe48abb8eeb386d93e7f1165ace1dd027f136a8a31edd2b20bc57a0c071d7"}, + {file = "bitarray-2.9.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:451ceecdb86bb95ae101b0d65c8c4524d692ae3666662fef8c89877ce17748c5"}, + {file = "bitarray-2.9.3-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f4d67d3e3de2aede737b12cd75a84963700c941b77b579c14bd05517e05d7a9f"}, + {file = "bitarray-2.9.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:2406d13ded84049b4238815a5821e44d6f58ba00fbb6b705b6ef8ccd88be8f03"}, + {file = "bitarray-2.9.3-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0db944fc2a048020fc940841ef46c0295b045d45a5a582cba69f78962a49a384"}, + {file = "bitarray-2.9.3-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25c603f141171a7d108773d5136d14e572c473e4cdb3fb464c39c8a138522eb2"}, + {file = "bitarray-2.9.3-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86c06b02705305cab0914d209caa24effda81316e2f2555a71a9aa399b75c5a5"}, + {file = "bitarray-2.9.3-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3ddda45b24a802eaaca8f794e6267ff2b62de5fe7b900b76d6f662d95192bebf"}, + {file = "bitarray-2.9.3-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:81490623950d04870c6dd4d7e6df2eb68dd04eca8bec327895ebee8bbe0cc3c7"}, + {file = "bitarray-2.9.3-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a9e69ac6a514cc574891c24a50847022dac2fef8c3f4df530f92820a07337755"}, + {file = "bitarray-2.9.3-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:545c695ee69d26b41351ced4c76244d8b6225669fc0af3652ff8ed5a6b28325d"}, + {file = "bitarray-2.9.3-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fbb2e6daabd2a64d091ac7460b0c5c5f9268199ae9a8ce32737cf5273987f1fa"}, + {file = "bitarray-2.9.3-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a969e5cf63144b944ee8d0a0739f53ef1ae54725b5e01258d690a8995d880526"}, + {file = "bitarray-2.9.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:73bbb9301ac9000f869c51db2cc5fcc6541985d3fcdcfe6e02f90c9e672a00be"}, + {file = "bitarray-2.9.3-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7c07e346926488a85a48542d898f4168f3587ec42379fef0d18be301e08a3f27"}, + {file = "bitarray-2.9.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a26d8a14cd8ee496306f2afac34833502dd1ae826355af309333b6f252b23fe"}, + {file = "bitarray-2.9.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cef148ed37c892395ca182d6a235524165a9f765f4283d0a1ced891e7c43c67a"}, + {file = "bitarray-2.9.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:94f35a8f0c8a50ee98a8bef9a070d0b68ecf623f20a2148cc039aba5557346a6"}, + {file = "bitarray-2.9.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:b03207460daae828e2743874c84264e8d96a8c6156490279092b624cd5d2de08"}, + {file = "bitarray-2.9.3.tar.gz", hash = "sha256:9eff55cf189b0c37ba97156a00d640eb7392db58a8049be6f26ff2712b93fa89"}, ] [[package]] @@ -264,33 +346,33 @@ bitarray = ">=2.9.0,<3.0.0" [[package]] name = "black" -version = "24.4.2" +version = "24.10.0" description = "The uncompromising code formatter." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "black-24.4.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dd1b5a14e417189db4c7b64a6540f31730713d173f0b63e55fabd52d61d8fdce"}, - {file = "black-24.4.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e537d281831ad0e71007dcdcbe50a71470b978c453fa41ce77186bbe0ed6021"}, - {file = "black-24.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eaea3008c281f1038edb473c1aa8ed8143a5535ff18f978a318f10302b254063"}, - {file = "black-24.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:7768a0dbf16a39aa5e9a3ded568bb545c8c2727396d063bbaf847df05b08cd96"}, - {file = "black-24.4.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:257d724c2c9b1660f353b36c802ccece186a30accc7742c176d29c146df6e474"}, - {file = "black-24.4.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bdde6f877a18f24844e381d45e9947a49e97933573ac9d4345399be37621e26c"}, - {file = "black-24.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e151054aa00bad1f4e1f04919542885f89f5f7d086b8a59e5000e6c616896ffb"}, - {file = "black-24.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:7e122b1c4fb252fd85df3ca93578732b4749d9be076593076ef4d07a0233c3e1"}, - {file = "black-24.4.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:accf49e151c8ed2c0cdc528691838afd217c50412534e876a19270fea1e28e2d"}, - {file = "black-24.4.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:88c57dc656038f1ab9f92b3eb5335ee9b021412feaa46330d5eba4e51fe49b04"}, - {file = "black-24.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be8bef99eb46d5021bf053114442914baeb3649a89dc5f3a555c88737e5e98fc"}, - {file = "black-24.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:415e686e87dbbe6f4cd5ef0fbf764af7b89f9057b97c908742b6008cc554b9c0"}, - {file = "black-24.4.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bf10f7310db693bb62692609b397e8d67257c55f949abde4c67f9cc574492cc7"}, - {file = "black-24.4.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:98e123f1d5cfd42f886624d84464f7756f60ff6eab89ae845210631714f6db94"}, - {file = "black-24.4.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:48a85f2cb5e6799a9ef05347b476cce6c182d6c71ee36925a6c194d074336ef8"}, - {file = "black-24.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:b1530ae42e9d6d5b670a34db49a94115a64596bc77710b1d05e9801e62ca0a7c"}, - {file = "black-24.4.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:37aae07b029fa0174d39daf02748b379399b909652a806e5708199bd93899da1"}, - {file = "black-24.4.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:da33a1a5e49c4122ccdfd56cd021ff1ebc4a1ec4e2d01594fef9b6f267a9e741"}, - {file = "black-24.4.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef703f83fc32e131e9bcc0a5094cfe85599e7109f896fe8bc96cc402f3eb4b6e"}, - {file = "black-24.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:b9176b9832e84308818a99a561e90aa479e73c523b3f77afd07913380ae2eab7"}, - {file = "black-24.4.2-py3-none-any.whl", hash = "sha256:d36ed1124bb81b32f8614555b34cc4259c3fbc7eec17870e8ff8ded335b58d8c"}, - {file = "black-24.4.2.tar.gz", hash = "sha256:c872b53057f000085da66a19c55d68f6f8ddcac2642392ad3a355878406fbd4d"}, + {file = "black-24.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e6668650ea4b685440857138e5fe40cde4d652633b1bdffc62933d0db4ed9812"}, + {file = "black-24.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1c536fcf674217e87b8cc3657b81809d3c085d7bf3ef262ead700da345bfa6ea"}, + {file = "black-24.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:649fff99a20bd06c6f727d2a27f401331dc0cc861fb69cde910fe95b01b5928f"}, + {file = "black-24.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:fe4d6476887de70546212c99ac9bd803d90b42fc4767f058a0baa895013fbb3e"}, + {file = "black-24.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5a2221696a8224e335c28816a9d331a6c2ae15a2ee34ec857dcf3e45dbfa99ad"}, + {file = "black-24.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f9da3333530dbcecc1be13e69c250ed8dfa67f43c4005fb537bb426e19200d50"}, + {file = "black-24.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4007b1393d902b48b36958a216c20c4482f601569d19ed1df294a496eb366392"}, + {file = "black-24.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:394d4ddc64782e51153eadcaaca95144ac4c35e27ef9b0a42e121ae7e57a9175"}, + {file = "black-24.10.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b5e39e0fae001df40f95bd8cc36b9165c5e2ea88900167bddf258bacef9bbdc3"}, + {file = "black-24.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d37d422772111794b26757c5b55a3eade028aa3fde43121ab7b673d050949d65"}, + {file = "black-24.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:14b3502784f09ce2443830e3133dacf2c0110d45191ed470ecb04d0f5f6fcb0f"}, + {file = "black-24.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:30d2c30dc5139211dda799758559d1b049f7f14c580c409d6ad925b74a4208a8"}, + {file = "black-24.10.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1cbacacb19e922a1d75ef2b6ccaefcd6e93a2c05ede32f06a21386a04cedb981"}, + {file = "black-24.10.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1f93102e0c5bb3907451063e08b9876dbeac810e7da5a8bfb7aeb5a9ef89066b"}, + {file = "black-24.10.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ddacb691cdcdf77b96f549cf9591701d8db36b2f19519373d60d31746068dbf2"}, + {file = "black-24.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:680359d932801c76d2e9c9068d05c6b107f2584b2a5b88831c83962eb9984c1b"}, + {file = "black-24.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:17374989640fbca88b6a448129cd1745c5eb8d9547b464f281b251dd00155ccd"}, + {file = "black-24.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:63f626344343083322233f175aaf372d326de8436f5928c042639a4afbbf1d3f"}, + {file = "black-24.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfa1d0cb6200857f1923b602f978386a3a2758a65b52e0950299ea014be6800"}, + {file = "black-24.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:2cd9c95431d94adc56600710f8813ee27eea544dd118d45896bb734e9d7a0dc7"}, + {file = "black-24.10.0-py3-none-any.whl", hash = "sha256:3bb2b7a1f7b685f85b11fed1ef10f8a9148bceb49853e47a294a3dd963c1dd7d"}, + {file = "black-24.10.0.tar.gz", hash = "sha256:846ea64c97afe3bc677b761787993be4991810ecc7a4a937816dd6bddedc4875"}, ] [package.dependencies] @@ -304,7 +386,7 @@ typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""} [package.extras] colorama = ["colorama (>=0.4.3)"] -d = ["aiohttp (>=3.7.4)", "aiohttp (>=3.7.4,!=3.9.0)"] +d = ["aiohttp (>=3.10)"] jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] uvloop = ["uvloop (>=0.15.2)"] @@ -328,74 +410,89 @@ coincurve = "*" [[package]] name = "certifi" -version = "2024.7.4" +version = "2024.8.30" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2024.7.4-py3-none-any.whl", hash = "sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90"}, - {file = "certifi-2024.7.4.tar.gz", hash = "sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b"}, + {file = "certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8"}, + {file = "certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9"}, ] [[package]] name = "cffi" -version = "1.16.0" +version = "1.17.1" description = "Foreign Function Interface for Python calling C code." optional = false python-versions = ">=3.8" files = [ - {file = "cffi-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088"}, - {file = "cffi-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614"}, - {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743"}, - {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d"}, - {file = "cffi-1.16.0-cp310-cp310-win32.whl", hash = "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a"}, - {file = "cffi-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1"}, - {file = "cffi-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404"}, - {file = "cffi-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e"}, - {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc"}, - {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb"}, - {file = "cffi-1.16.0-cp311-cp311-win32.whl", hash = "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab"}, - {file = "cffi-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba"}, - {file = "cffi-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956"}, - {file = "cffi-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969"}, - {file = "cffi-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520"}, - {file = "cffi-1.16.0-cp312-cp312-win32.whl", hash = "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b"}, - {file = "cffi-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235"}, - {file = "cffi-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324"}, - {file = "cffi-1.16.0-cp38-cp38-win32.whl", hash = "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a"}, - {file = "cffi-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36"}, - {file = "cffi-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed"}, - {file = "cffi-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098"}, - {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000"}, - {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe"}, - {file = "cffi-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4"}, - {file = "cffi-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8"}, - {file = "cffi-1.16.0.tar.gz", hash = "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0"}, + {file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"}, + {file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be"}, + {file = "cffi-1.17.1-cp310-cp310-win32.whl", hash = "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c"}, + {file = "cffi-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15"}, + {file = "cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401"}, + {file = "cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b"}, + {file = "cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655"}, + {file = "cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0"}, + {file = "cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4"}, + {file = "cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93"}, + {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3"}, + {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8"}, + {file = "cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65"}, + {file = "cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903"}, + {file = "cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e"}, + {file = "cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd"}, + {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed"}, + {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9"}, + {file = "cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d"}, + {file = "cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a"}, + {file = "cffi-1.17.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1"}, + {file = "cffi-1.17.1-cp38-cp38-win32.whl", hash = "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8"}, + {file = "cffi-1.17.1-cp38-cp38-win_amd64.whl", hash = "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1"}, + {file = "cffi-1.17.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16"}, + {file = "cffi-1.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e"}, + {file = "cffi-1.17.1-cp39-cp39-win32.whl", hash = "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7"}, + {file = "cffi-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662"}, + {file = "cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824"}, ] [package.dependencies] @@ -414,101 +511,116 @@ files = [ [[package]] name = "charset-normalizer" -version = "3.3.2" +version = "3.4.0" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false python-versions = ">=3.7.0" files = [ - {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"}, - {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5ed2e36c3e9b4f21dd9422f6893dec0abf2cca553af509b10cd630f878d3eb99"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40d3ff7fc90b98c637bda91c89d51264a3dcf210cade3a2c6f838c7268d7a4ca"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1110e22af8ca26b90bd6364fe4c763329b0ebf1ee213ba32b68c73de5752323d"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:86f4e8cca779080f66ff4f191a685ced73d2f72d50216f7112185dc02b90b9b7"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f683ddc7eedd742e2889d2bfb96d69573fde1d92fcb811979cdb7165bb9c7d3"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27623ba66c183eca01bf9ff833875b459cad267aeeb044477fedac35e19ba907"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f606a1881d2663630ea5b8ce2efe2111740df4b687bd78b34a8131baa007f79b"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0b309d1747110feb25d7ed6b01afdec269c647d382c857ef4663bbe6ad95a912"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:136815f06a3ae311fae551c3df1f998a1ebd01ddd424aa5603a4336997629e95"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:14215b71a762336254351b00ec720a8e85cada43b987da5a042e4ce3e82bd68e"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:79983512b108e4a164b9c8d34de3992f76d48cadc9554c9e60b43f308988aabe"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-win32.whl", hash = "sha256:c94057af19bc953643a33581844649a7fdab902624d2eb739738a30e2b3e60fc"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:55f56e2ebd4e3bc50442fbc0888c9d8c94e4e06a933804e2af3e89e2f9c1c749"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-win32.whl", hash = "sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-win32.whl", hash = "sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-win32.whl", hash = "sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:dbe03226baf438ac4fda9e2d0715022fd579cb641c4cf639fa40d53b2fe6f3e2"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd9a8bd8900e65504a305bf8ae6fa9fbc66de94178c420791d0293702fce2df7"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8831399554b92b72af5932cdbbd4ddc55c55f631bb13ff8fe4e6536a06c5c51"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a14969b8691f7998e74663b77b4c36c0337cb1df552da83d5c9004a93afdb574"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dcaf7c1524c0542ee2fc82cc8ec337f7a9f7edee2532421ab200d2b920fc97cf"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:425c5f215d0eecee9a56cdb703203dda90423247421bf0d67125add85d0c4455"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:d5b054862739d276e09928de37c79ddeec42a6e1bfc55863be96a36ba22926f6"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:f3e73a4255342d4eb26ef6df01e3962e73aa29baa3124a8e824c5d3364a65748"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:2f6c34da58ea9c1a9515621f4d9ac379871a8f21168ba1b5e09d74250de5ad62"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:f09cb5a7bbe1ecae6e87901a2eb23e0256bb524a79ccc53eb0b7629fbe7677c4"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:0099d79bdfcf5c1f0c2c72f91516702ebf8b0b8ddd8905f97a8aecf49712c621"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-win32.whl", hash = "sha256:9c98230f5042f4945f957d006edccc2af1e03ed5e37ce7c373f00a5a4daa6149"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:62f60aebecfc7f4b82e3f639a7d1433a20ec32824db2199a11ad4f5e146ef5ee"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:af73657b7a68211996527dbfeffbb0864e043d270580c5aef06dc4b659a4b578"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cab5d0b79d987c67f3b9e9c53f54a61360422a5a0bc075f43cab5621d530c3b6"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9289fd5dddcf57bab41d044f1756550f9e7cf0c8e373b8cdf0ce8773dc4bd417"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b493a043635eb376e50eedf7818f2f322eabbaa974e948bd8bdd29eb7ef2a51"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fa2566ca27d67c86569e8c85297aaf413ffab85a8960500f12ea34ff98e4c41"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8e538f46104c815be19c975572d74afb53f29650ea2025bbfaef359d2de2f7f"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fd30dc99682dc2c603c2b315bded2799019cea829f8bf57dc6b61efde6611c8"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2006769bd1640bdf4d5641c69a3d63b71b81445473cac5ded39740a226fa88ab"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:dc15e99b2d8a656f8e666854404f1ba54765871104e50c8e9813af8a7db07f12"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:ab2e5bef076f5a235c3774b4f4028a680432cded7cad37bba0fd90d64b187d19"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:4ec9dd88a5b71abfc74e9df5ebe7921c35cbb3b641181a531ca65cdb5e8e4dea"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:43193c5cda5d612f247172016c4bb71251c784d7a4d9314677186a838ad34858"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:aa693779a8b50cd97570e5a0f343538a8dbd3e496fa5dcb87e29406ad0299654"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-win32.whl", hash = "sha256:7706f5850360ac01d80c89bcef1640683cc12ed87f42579dab6c5d3ed6888613"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:c3e446d253bd88f6377260d07c895816ebf33ffffd56c1c792b13bff9c3e1ade"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:980b4f289d1d90ca5efcf07958d3eb38ed9c0b7676bf2831a54d4f66f9c27dfa"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f28f891ccd15c514a0981f3b9db9aa23d62fe1a99997512b0491d2ed323d229a"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8aacce6e2e1edcb6ac625fb0f8c3a9570ccc7bfba1f63419b3769ccf6a00ed0"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd7af3717683bea4c87acd8c0d3d5b44d56120b26fd3f8a692bdd2d5260c620a"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ff2ed8194587faf56555927b3aa10e6fb69d931e33953943bc4f837dfee2242"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e91f541a85298cf35433bf66f3fab2a4a2cff05c127eeca4af174f6d497f0d4b"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:309a7de0a0ff3040acaebb35ec45d18db4b28232f21998851cfa709eeff49d62"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:285e96d9d53422efc0d7a17c60e59f37fbf3dfa942073f666db4ac71e8d726d0"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:5d447056e2ca60382d460a604b6302d8db69476fd2015c81e7c35417cfabe4cd"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:20587d20f557fe189b7947d8e7ec5afa110ccf72a3128d61a2a387c3313f46be"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:130272c698667a982a5d0e626851ceff662565379baf0ff2cc58067b81d4f11d"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ab22fbd9765e6954bc0bcff24c25ff71dcbfdb185fcdaca49e81bac68fe724d3"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7782afc9b6b42200f7362858f9e73b1f8316afb276d316336c0ec3bd73312742"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-win32.whl", hash = "sha256:2de62e8801ddfff069cd5c504ce3bc9672b23266597d4e4f50eda28846c322f2"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:95c3c157765b031331dd4db3c775e58deaee050a3042fcad72cbc4189d7c8dca"}, + {file = "charset_normalizer-3.4.0-py3-none-any.whl", hash = "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079"}, + {file = "charset_normalizer-3.4.0.tar.gz", hash = "sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e"}, ] [[package]] @@ -527,59 +639,70 @@ colorama = {version = "*", markers = "platform_system == \"Windows\""} [[package]] name = "coincurve" -version = "18.0.0" +version = "20.0.0" description = "Cross-platform Python CFFI bindings for libsecp256k1" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "coincurve-18.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0b1a42eba91b9e4f833309e94bc6a270b1700cb4567d4809ef91f00968b57925"}, - {file = "coincurve-18.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:116bf1b60a6e72e23c6b153d7c79f0e565d82973d917a3cecf655ffb29263163"}, - {file = "coincurve-18.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d53e2a268142924c24e9b786b3e6c3603fae54bb8211560036b0e9ce6a9f2dbc"}, - {file = "coincurve-18.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b31ab366fadff16ecfdde96ffc07e70fee83850f88bd1f985a8b4977a68bbfb"}, - {file = "coincurve-18.0.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07e3c37cfadac6896668a130ea46296a3dfdeea0160fd66a51e377ad00795269"}, - {file = "coincurve-18.0.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:f3e5f2a2d774050b3ea8bf2167f2d598fde58d7690779931516714d98b65d884"}, - {file = "coincurve-18.0.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:83379dd70291480df2052554851bfd17444c003aef7c4bb02d96d73eec69fe28"}, - {file = "coincurve-18.0.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:33678f6b43edbeab6605584c725305f4f814239780c53eba0f8e4bc4a52b1d1a"}, - {file = "coincurve-18.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f40646d5f29ac9026f8cc1b368bc9ab68710fad055b64fbec020f9bbfc99b242"}, - {file = "coincurve-18.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:779da694dea1b1d09e16b00e079f6a1195290ce9568f39c95cddf35f1f49ec49"}, - {file = "coincurve-18.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7844f01904e32317a00696a27fd771860e53a2fa62e5c66eace9337d2742c9e6"}, - {file = "coincurve-18.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:257c6171cd0301c119ef41360f0d0c2fb5cc288717b33d3bd5482a4c9ae04551"}, - {file = "coincurve-18.0.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f8bcb9c40fd730cf377fa448f1304355d6497fb3d00b7b0a69a10dfcc14a6d28"}, - {file = "coincurve-18.0.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e3abb7f65e2b5fb66a15e374faeaafe6700fdb83fb66d1873ddff91c395a3b74"}, - {file = "coincurve-18.0.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:f44b9ba588b34795d1b4074f9a9fa372adef3fde58300bf32f40a69e8cd72a23"}, - {file = "coincurve-18.0.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:908467330cd3047c71105a08394c4f3e7dce76e4371b030ba8b0ef863013e3ca"}, - {file = "coincurve-18.0.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:599b1b3cf097cae920d97f31a5b8e8aff185ca8fa5d8a785b2edf7b199fb9731"}, - {file = "coincurve-18.0.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d2c20d108580bce5efedb980688031462168f4de2446de95898b48a249127a2"}, - {file = "coincurve-18.0.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eba563f7f70c10323227d1890072172bd84df6f814c9a6b012033b214426b6cf"}, - {file = "coincurve-18.0.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:412a06b7d1b8229f25318f05e76310298da5ad55d73851eabac7ddfdcdc5bff4"}, - {file = "coincurve-18.0.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:286969b6f789bbd9d744d28350a3630c1cb3ee045263469a28892f70a4a6654a"}, - {file = "coincurve-18.0.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:14700463009c7d799a746929728223aa53ff1ece394ea408516d98d637434883"}, - {file = "coincurve-18.0.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:7f1142252e870f091b2c2c21cc1fadfdd29af23d02e99f29add0f14d1ba94b4c"}, - {file = "coincurve-18.0.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cd11d2ca5b7e989c5ce1af217a2ad78c19c21afca786f198d1b1a408d6f408dc"}, - {file = "coincurve-18.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:1bce17d7475cee9db2c2fa7af07eaab582732b378acf6dcaee417de1df2d8661"}, - {file = "coincurve-18.0.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ab662b67454fea7f0a5ae855ba6ad9410bcaebe68b97f4dade7b5944dec3a11"}, - {file = "coincurve-18.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:23b9ced9cce32dabb4bc15fa6449252fa51efddf0268481973e4c3772a5a68c6"}, - {file = "coincurve-18.0.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d05641cf31d68514c47cb54105d20acbae79fc3ee3942454eaaf411babb3f880"}, - {file = "coincurve-18.0.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a7b31efe56b3f6434828ad5f6ecde4a95747bb69b59032746482eebb8f3456a4"}, - {file = "coincurve-18.0.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:2d95103ed43df855121cd925869ae2589360a8d94fcd61b236958deacfb9a359"}, - {file = "coincurve-18.0.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:abeb4c1d78e1a81a3f1c99a406cd858669582ada2d976e876ef694f57dec95ca"}, - {file = "coincurve-18.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fceca9d6ecaa1e8f891675e4f4ff530d54e41c648fc6e8a816835ffa640fa899"}, - {file = "coincurve-18.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e009f06287507158f16c82cc313c0f3bfd0e9ec1e82d1a4d5fa1c5b6c0060f69"}, - {file = "coincurve-18.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a0c0c1e492ef08efe99d25a23d535e2bff667bbef43d71a6f8893ae811b3d81"}, - {file = "coincurve-18.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3caf58877bcf41eb4c1be7a2d54317f0b31541d99ba248dae28821b19c52a0db"}, - {file = "coincurve-18.0.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8964e680c622a2b5eea940abdf51c77c1bd3d4fde2a04cec2420bf91981b198a"}, - {file = "coincurve-18.0.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:73e464e0ace77c686fdc54590e5592905b6802f9fc20a0c023f0b1585669d6a3"}, - {file = "coincurve-18.0.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:ba9eaddd50a2ce0d891af7cee11c2e048d1f0f44bf87db00a5c4b1eee7e3391b"}, - {file = "coincurve-18.0.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8290903d4629f27f9f3cdeec72ffa97536c5a6ed5ba7e3413b2707991c650fbe"}, - {file = "coincurve-18.0.0-py3-none-win32.whl", hash = "sha256:c60690bd7704d8563968d2dded33eb514875a52b5964f085409965ad041b2555"}, - {file = "coincurve-18.0.0-py3-none-win_amd64.whl", hash = "sha256:704d1abf2e78def33988368592233a8ec9b98bfc45dfa2ec9e898adfad46e5ad"}, - {file = "coincurve-18.0.0.tar.gz", hash = "sha256:c86626afe417a09d8e80e56780efcae3ae516203b23b5ade84813916e1c94fc1"}, + {file = "coincurve-20.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d559b22828638390118cae9372a1bb6f6594f5584c311deb1de6a83163a0919b"}, + {file = "coincurve-20.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:33d7f6ebd90fcc550f819f7f2cce2af525c342aac07f0ccda46ad8956ad9d99b"}, + {file = "coincurve-20.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22d70dd55d13fd427418eb41c20fde0a20a5e5f016e2b1bb94710701e759e7e0"}, + {file = "coincurve-20.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46f18d481eaae72c169f334cde1fd22011a884e0c9c6adc3fdc1fd13df8236a3"}, + {file = "coincurve-20.0.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9de1ec57f43c3526bc462be58fb97910dc1fdd5acab6c71eda9f9719a5bd7489"}, + {file = "coincurve-20.0.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:a6f007c44c726b5c0b3724093c0d4fb8e294f6b6869beb02d7473b21777473a3"}, + {file = "coincurve-20.0.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:0ff1f3b81330db5092c24da2102e4fcba5094f14945b3eb40746456ceabdd6d9"}, + {file = "coincurve-20.0.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:82f7de97694d9343f26bd1c8e081b168e5f525894c12445548ce458af227f536"}, + {file = "coincurve-20.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:e905b4b084b4f3b61e5a5d58ac2632fd1d07b7b13b4c6d778335a6ca1dafd7a3"}, + {file = "coincurve-20.0.0-cp310-cp310-win_arm64.whl", hash = "sha256:3657bb5ed0baf1cf8cf356e7d44aa90a7902cc3dd4a435c6d4d0bed0553ad4f7"}, + {file = "coincurve-20.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:44087d1126d43925bf9a2391ce5601bf30ce0dba4466c239172dc43226696018"}, + {file = "coincurve-20.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5ccf0ba38b0f307a9b3ce28933f6c71dc12ef3a0985712ca09f48591afd597c8"}, + {file = "coincurve-20.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:566bc5986debdf8572b6be824fd4de03d533c49f3de778e29f69017ae3fe82d8"}, + {file = "coincurve-20.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f4d70283168e146f025005c15406086513d5d35e89a60cf4326025930d45013a"}, + {file = "coincurve-20.0.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:763c6122dd7d5e7a81c86414ce360dbe9a2d4afa1ca6c853ee03d63820b3d0c5"}, + {file = "coincurve-20.0.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f00c361c356bcea386d47a191bb8ac60429f4b51c188966a201bfecaf306ff7f"}, + {file = "coincurve-20.0.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4af57bdadd2e64d117dd0b33cfefe76e90c7a6c496a7b034fc65fd01ec249b15"}, + {file = "coincurve-20.0.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a26437b7cbde13fb6e09261610b788ca2a0ca2195c62030afd1e1e0d1a62e035"}, + {file = "coincurve-20.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:ed51f8bba35e6c7676ad65539c3dbc35acf014fc402101fa24f6b0a15a74ab9e"}, + {file = "coincurve-20.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:594b840fc25d74118407edbbbc754b815f1bba9759dbf4f67f1c2b78396df2d3"}, + {file = "coincurve-20.0.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:4df4416a6c0370d777aa725a25b14b04e45aa228da1251c258ff91444643f688"}, + {file = "coincurve-20.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1ccc3e4db55abf3fc0e604a187fdb05f0702bc5952e503d9a75f4ae6eeb4cb3a"}, + {file = "coincurve-20.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac8335b1658a2ef5b3eb66d52647742fe8c6f413ad5b9d5310d7ea6d8060d40f"}, + {file = "coincurve-20.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c7ac025e485a0229fd5394e0bf6b4a75f8a4f6cee0dcf6f0b01a2ef05c5210ff"}, + {file = "coincurve-20.0.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e46e3f1c21b3330857bcb1a3a5b942f645c8bce912a8a2b252216f34acfe4195"}, + {file = "coincurve-20.0.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:df9ff9b17a1d27271bf476cf3fa92df4c151663b11a55d8cea838b8f88d83624"}, + {file = "coincurve-20.0.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:4155759f071375699282e03b3d95fb473ee05c022641c077533e0d906311e57a"}, + {file = "coincurve-20.0.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:0530b9dd02fc6f6c2916716974b79bdab874227f560c422801ade290e3fc5013"}, + {file = "coincurve-20.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:eacf9c0ce8739c84549a89c083b1f3526c8780b84517ee75d6b43d276e55f8a0"}, + {file = "coincurve-20.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:52a67bfddbd6224dfa42085c88ad176559801b57d6a8bd30d92ee040de88b7b3"}, + {file = "coincurve-20.0.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:61e951b1d695b62376f60519a84c4facaf756eeb9c5aff975bea0942833f185d"}, + {file = "coincurve-20.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4e9e548db77f4ea34c0d748dddefc698adb0ee3fab23ed19f80fb2118dac70f6"}, + {file = "coincurve-20.0.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8cdbf0da0e0809366fdfff236b7eb6e663669c7b1f46361a4c4d05f5b7e94c57"}, + {file = "coincurve-20.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d72222b4ecd3952e8ffcbf59bc7e0d1b181161ba170b60e5c8e1f359a43bbe7e"}, + {file = "coincurve-20.0.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9add43c4807f0c17a940ce4076334c28f51d09c145cd478400e89dcfb83fb59d"}, + {file = "coincurve-20.0.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:bcc94cceea6ec8863815134083e6221a034b1ecef822d0277cf6ad2e70009b7f"}, + {file = "coincurve-20.0.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1ffbdfef6a6d147988eabaed681287a9a7e6ba45ecc0a8b94ba62ad0a7656d97"}, + {file = "coincurve-20.0.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:13335c19c7e5f36eaba2a53c68073d981980d7dc7abfee68d29f2da887ccd24e"}, + {file = "coincurve-20.0.0-cp38-cp38-win_amd64.whl", hash = "sha256:7fbfb8d16cf2bea2cf48fc5246d4cb0a06607d73bb5c57c007c9aed7509f855e"}, + {file = "coincurve-20.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4870047704cddaae7f0266a549c927407c2ba0ec92d689e3d2b511736812a905"}, + {file = "coincurve-20.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:81ce41263517b0a9f43cd570c87720b3c13324929584fa28d2e4095969b6015d"}, + {file = "coincurve-20.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:572083ccce6c7b514d482f25f394368f4ae888f478bd0b067519d33160ea2fcc"}, + {file = "coincurve-20.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee5bc78a31a2f1370baf28aaff3949bc48f940a12b0359d1cd2c4115742874e6"}, + {file = "coincurve-20.0.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2895d032e281c4e747947aae4bcfeef7c57eabfd9be22886c0ca4e1365c7c1f"}, + {file = "coincurve-20.0.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d3e2f21957ada0e1742edbde117bb41758fa8691b69c8d186c23e9e522ea71cd"}, + {file = "coincurve-20.0.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:c2baa26b1aad1947ca07b3aa9e6a98940c5141c6bdd0f9b44d89e36da7282ffa"}, + {file = "coincurve-20.0.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7eacc7944ddf9e2b7448ecbe84753841ab9874b8c332a4f5cc3b2f184db9f4a2"}, + {file = "coincurve-20.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:c293c095dc690178b822cadaaeb81de3cc0d28f8bdf8216ed23551dcce153a26"}, + {file = "coincurve-20.0.0-cp39-cp39-win_arm64.whl", hash = "sha256:11a47083a0b7092d3eb50929f74ffd947c4a5e7035796b81310ea85289088c7a"}, + {file = "coincurve-20.0.0.tar.gz", hash = "sha256:872419e404300302e938849b6b92a196fabdad651060b559dc310e52f8392829"}, ] [package.dependencies] asn1crypto = "*" cffi = ">=1.3.0" +[package.extras] +dev = ["coverage", "pytest", "pytest-benchmark"] + [[package]] name = "colorama" version = "0.4.6" @@ -593,94 +716,103 @@ files = [ [[package]] name = "cryptography" -version = "41.0.7" +version = "42.0.8" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." optional = false python-versions = ">=3.7" files = [ - {file = "cryptography-41.0.7-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:3c78451b78313fa81607fa1b3f1ae0a5ddd8014c38a02d9db0616133987b9cdf"}, - {file = "cryptography-41.0.7-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:928258ba5d6f8ae644e764d0f996d61a8777559f72dfeb2eea7e2fe0ad6e782d"}, - {file = "cryptography-41.0.7-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5a1b41bc97f1ad230a41657d9155113c7521953869ae57ac39ac7f1bb471469a"}, - {file = "cryptography-41.0.7-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:841df4caa01008bad253bce2a6f7b47f86dc9f08df4b433c404def869f590a15"}, - {file = "cryptography-41.0.7-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:5429ec739a29df2e29e15d082f1d9ad683701f0ec7709ca479b3ff2708dae65a"}, - {file = "cryptography-41.0.7-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:43f2552a2378b44869fe8827aa19e69512e3245a219104438692385b0ee119d1"}, - {file = "cryptography-41.0.7-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:af03b32695b24d85a75d40e1ba39ffe7db7ffcb099fe507b39fd41a565f1b157"}, - {file = "cryptography-41.0.7-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:49f0805fc0b2ac8d4882dd52f4a3b935b210935d500b6b805f321addc8177406"}, - {file = "cryptography-41.0.7-cp37-abi3-win32.whl", hash = "sha256:f983596065a18a2183e7f79ab3fd4c475205b839e02cbc0efbbf9666c4b3083d"}, - {file = "cryptography-41.0.7-cp37-abi3-win_amd64.whl", hash = "sha256:90452ba79b8788fa380dfb587cca692976ef4e757b194b093d845e8d99f612f2"}, - {file = "cryptography-41.0.7-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:079b85658ea2f59c4f43b70f8119a52414cdb7be34da5d019a77bf96d473b960"}, - {file = "cryptography-41.0.7-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:b640981bf64a3e978a56167594a0e97db71c89a479da8e175d8bb5be5178c003"}, - {file = "cryptography-41.0.7-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e3114da6d7f95d2dee7d3f4eec16dacff819740bbab931aff8648cb13c5ff5e7"}, - {file = "cryptography-41.0.7-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d5ec85080cce7b0513cfd233914eb8b7bbd0633f1d1703aa28d1dd5a72f678ec"}, - {file = "cryptography-41.0.7-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:7a698cb1dac82c35fcf8fe3417a3aaba97de16a01ac914b89a0889d364d2f6be"}, - {file = "cryptography-41.0.7-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:37a138589b12069efb424220bf78eac59ca68b95696fc622b6ccc1c0a197204a"}, - {file = "cryptography-41.0.7-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:68a2dec79deebc5d26d617bfdf6e8aab065a4f34934b22d3b5010df3ba36612c"}, - {file = "cryptography-41.0.7-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:09616eeaef406f99046553b8a40fbf8b1e70795a91885ba4c96a70793de5504a"}, - {file = "cryptography-41.0.7-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:48a0476626da912a44cc078f9893f292f0b3e4c739caf289268168d8f4702a39"}, - {file = "cryptography-41.0.7-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c7f3201ec47d5207841402594f1d7950879ef890c0c495052fa62f58283fde1a"}, - {file = "cryptography-41.0.7-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c5ca78485a255e03c32b513f8c2bc39fedb7f5c5f8535545bdc223a03b24f248"}, - {file = "cryptography-41.0.7-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:d6c391c021ab1f7a82da5d8d0b3cee2f4b2c455ec86c8aebbc84837a631ff309"}, - {file = "cryptography-41.0.7.tar.gz", hash = "sha256:13f93ce9bea8016c253b34afc6bd6a75993e5c40672ed5405a9c832f0d4a00bc"}, + {file = "cryptography-42.0.8-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:81d8a521705787afe7a18d5bfb47ea9d9cc068206270aad0b96a725022e18d2e"}, + {file = "cryptography-42.0.8-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:961e61cefdcb06e0c6d7e3a1b22ebe8b996eb2bf50614e89384be54c48c6b63d"}, + {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e3ec3672626e1b9e55afd0df6d774ff0e953452886e06e0f1eb7eb0c832e8902"}, + {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e599b53fd95357d92304510fb7bda8523ed1f79ca98dce2f43c115950aa78801"}, + {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:5226d5d21ab681f432a9c1cf8b658c0cb02533eece706b155e5fbd8a0cdd3949"}, + {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:6b7c4f03ce01afd3b76cf69a5455caa9cfa3de8c8f493e0d3ab7d20611c8dae9"}, + {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:2346b911eb349ab547076f47f2e035fc8ff2c02380a7cbbf8d87114fa0f1c583"}, + {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:ad803773e9df0b92e0a817d22fd8a3675493f690b96130a5e24f1b8fabbea9c7"}, + {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:2f66d9cd9147ee495a8374a45ca445819f8929a3efcd2e3df6428e46c3cbb10b"}, + {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:d45b940883a03e19e944456a558b67a41160e367a719833c53de6911cabba2b7"}, + {file = "cryptography-42.0.8-cp37-abi3-win32.whl", hash = "sha256:a0c5b2b0585b6af82d7e385f55a8bc568abff8923af147ee3c07bd8b42cda8b2"}, + {file = "cryptography-42.0.8-cp37-abi3-win_amd64.whl", hash = "sha256:57080dee41209e556a9a4ce60d229244f7a66ef52750f813bfbe18959770cfba"}, + {file = "cryptography-42.0.8-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:dea567d1b0e8bc5764b9443858b673b734100c2871dc93163f58c46a97a83d28"}, + {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4783183f7cb757b73b2ae9aed6599b96338eb957233c58ca8f49a49cc32fd5e"}, + {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0608251135d0e03111152e41f0cc2392d1e74e35703960d4190b2e0f4ca9c70"}, + {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:dc0fdf6787f37b1c6b08e6dfc892d9d068b5bdb671198c72072828b80bd5fe4c"}, + {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:9c0c1716c8447ee7dbf08d6db2e5c41c688544c61074b54fc4564196f55c25a7"}, + {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:fff12c88a672ab9c9c1cf7b0c80e3ad9e2ebd9d828d955c126be4fd3e5578c9e"}, + {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:cafb92b2bc622cd1aa6a1dce4b93307792633f4c5fe1f46c6b97cf67073ec961"}, + {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:31f721658a29331f895a5a54e7e82075554ccfb8b163a18719d342f5ffe5ecb1"}, + {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b297f90c5723d04bcc8265fc2a0f86d4ea2e0f7ab4b6994459548d3a6b992a14"}, + {file = "cryptography-42.0.8-cp39-abi3-win32.whl", hash = "sha256:2f88d197e66c65be5e42cd72e5c18afbfae3f741742070e3019ac8f4ac57262c"}, + {file = "cryptography-42.0.8-cp39-abi3-win_amd64.whl", hash = "sha256:fa76fbb7596cc5839320000cdd5d0955313696d9511debab7ee7278fc8b5c84a"}, + {file = "cryptography-42.0.8-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:ba4f0a211697362e89ad822e667d8d340b4d8d55fae72cdd619389fb5912eefe"}, + {file = "cryptography-42.0.8-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:81884c4d096c272f00aeb1f11cf62ccd39763581645b0812e99a91505fa48e0c"}, + {file = "cryptography-42.0.8-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c9bb2ae11bfbab395bdd072985abde58ea9860ed84e59dbc0463a5d0159f5b71"}, + {file = "cryptography-42.0.8-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:7016f837e15b0a1c119d27ecd89b3515f01f90a8615ed5e9427e30d9cdbfed3d"}, + {file = "cryptography-42.0.8-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5a94eccb2a81a309806027e1670a358b99b8fe8bfe9f8d329f27d72c094dde8c"}, + {file = "cryptography-42.0.8-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:dec9b018df185f08483f294cae6ccac29e7a6e0678996587363dc352dc65c842"}, + {file = "cryptography-42.0.8-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:343728aac38decfdeecf55ecab3264b015be68fc2816ca800db649607aeee648"}, + {file = "cryptography-42.0.8-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:013629ae70b40af70c9a7a5db40abe5d9054e6f4380e50ce769947b73bf3caad"}, + {file = "cryptography-42.0.8.tar.gz", hash = "sha256:8d09d05439ce7baa8e9e95b07ec5b6c886f548deb7e0f69ef25f64b3bce842f2"}, ] [package.dependencies] -cffi = ">=1.12" +cffi = {version = ">=1.12", markers = "platform_python_implementation != \"PyPy\""} [package.extras] docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.1.1)"] -docstest = ["pyenchant (>=1.6.11)", "sphinxcontrib-spelling (>=4.0.1)", "twine (>=1.12.0)"] +docstest = ["pyenchant (>=1.6.11)", "readme-renderer", "sphinxcontrib-spelling (>=4.0.1)"] nox = ["nox"] -pep8test = ["black", "check-sdist", "mypy", "ruff"] +pep8test = ["check-sdist", "click", "mypy", "ruff"] sdist = ["build"] ssh = ["bcrypt (>=3.1.5)"] -test = ["pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] +test = ["certifi", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] test-randomorder = ["pytest-randomly"] [[package]] name = "deprecated" -version = "1.2.14" +version = "1.2.15" description = "Python @deprecated decorator to deprecate old python classes, functions or methods." optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" files = [ - {file = "Deprecated-1.2.14-py2.py3-none-any.whl", hash = "sha256:6fac8b097794a90302bdbb17b9b815e732d3c4720583ff1b198499d78470466c"}, - {file = "Deprecated-1.2.14.tar.gz", hash = "sha256:e5323eb936458dccc2582dc6f9c322c852a775a27065ff2b0c4970b9d53d01b3"}, + {file = "Deprecated-1.2.15-py2.py3-none-any.whl", hash = "sha256:353bc4a8ac4bfc96800ddab349d89c25dec1079f65fd53acdcc1e0b975b21320"}, + {file = "deprecated-1.2.15.tar.gz", hash = "sha256:683e561a90de76239796e6b6feac66b99030d2dd3fcf61ef996330f14bbb9b0d"}, ] [package.dependencies] wrapt = ">=1.10,<2" [package.extras] -dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "sphinx (<2)", "tox"] +dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "jinja2 (>=3.0.3,<3.1.0)", "setuptools", "sphinx (<2)", "tox"] [[package]] name = "distlib" -version = "0.3.8" +version = "0.3.9" description = "Distribution utilities" optional = false python-versions = "*" files = [ - {file = "distlib-0.3.8-py2.py3-none-any.whl", hash = "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784"}, - {file = "distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64"}, + {file = "distlib-0.3.9-py2.py3-none-any.whl", hash = "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87"}, + {file = "distlib-0.3.9.tar.gz", hash = "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403"}, ] [[package]] name = "dnspython" -version = "2.6.1" +version = "2.7.0" description = "DNS toolkit" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "dnspython-2.6.1-py3-none-any.whl", hash = "sha256:5ef3b9680161f6fa89daf8ad451b5f1a33b18ae8a1c6778cdf4b43f08c0a6e50"}, - {file = "dnspython-2.6.1.tar.gz", hash = "sha256:e8f0f9c23a7b7cb99ded64e6c3a6f3e701d78f50c55e002b839dea7225cff7cc"}, + {file = "dnspython-2.7.0-py3-none-any.whl", hash = "sha256:b4c34b7d10b51bcc3a5071e7b8dee77939f1e878477eeecc965e9835f63c6c86"}, + {file = "dnspython-2.7.0.tar.gz", hash = "sha256:ce9c432eda0dc91cf618a5cedf1a4e142651196bbcd2c80e89ed5a907e5cfaf1"}, ] [package.extras] -dev = ["black (>=23.1.0)", "coverage (>=7.0)", "flake8 (>=7)", "mypy (>=1.8)", "pylint (>=3)", "pytest (>=7.4)", "pytest-cov (>=4.1.0)", "sphinx (>=7.2.0)", "twine (>=4.0.0)", "wheel (>=0.42.0)"] -dnssec = ["cryptography (>=41)"] +dev = ["black (>=23.1.0)", "coverage (>=7.0)", "flake8 (>=7)", "hypercorn (>=0.16.0)", "mypy (>=1.8)", "pylint (>=3)", "pytest (>=7.4)", "pytest-cov (>=4.1.0)", "quart-trio (>=0.11.0)", "sphinx (>=7.2.0)", "sphinx-rtd-theme (>=2.0.0)", "twine (>=4.0.0)", "wheel (>=0.42.0)"] +dnssec = ["cryptography (>=43)"] doh = ["h2 (>=4.1.0)", "httpcore (>=1.0.0)", "httpx (>=0.26.0)"] -doq = ["aioquic (>=0.9.25)"] -idna = ["idna (>=3.6)"] +doq = ["aioquic (>=1.0.0)"] +idna = ["idna (>=3.7)"] trio = ["trio (>=0.23)"] wmi = ["wmi (>=1.5.1)"] @@ -767,23 +899,23 @@ test = ["pytest (>=6)"] [[package]] name = "fastapi" -version = "0.112.0" +version = "0.115.2" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" optional = false python-versions = ">=3.8" files = [ - {file = "fastapi-0.112.0-py3-none-any.whl", hash = "sha256:3487ded9778006a45834b8c816ec4a48d522e2631ca9e75ec5a774f1b052f821"}, - {file = "fastapi-0.112.0.tar.gz", hash = "sha256:d262bc56b7d101d1f4e8fc0ad2ac75bb9935fec504d2b7117686cec50710cf05"}, + {file = "fastapi-0.115.2-py3-none-any.whl", hash = "sha256:61704c71286579cc5a598763905928f24ee98bfcc07aabe84cfefb98812bbc86"}, + {file = "fastapi-0.115.2.tar.gz", hash = "sha256:3995739e0b09fa12f984bce8fa9ae197b35d433750d3d312422d846e283697ee"}, ] [package.dependencies] pydantic = ">=1.7.4,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0 || >2.0.0,<2.0.1 || >2.0.1,<2.1.0 || >2.1.0,<3.0.0" -starlette = ">=0.37.2,<0.38.0" +starlette = ">=0.37.2,<0.41.0" typing-extensions = ">=4.8.0" [package.extras] -all = ["email_validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.5)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.7)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] -standard = ["email_validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.5)", "httpx (>=0.23.0)", "jinja2 (>=2.11.2)", "python-multipart (>=0.0.7)", "uvicorn[standard] (>=0.12.0)"] +all = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.5)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.7)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] +standard = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.5)", "httpx (>=0.23.0)", "jinja2 (>=2.11.2)", "python-multipart (>=0.0.7)", "uvicorn[standard] (>=0.12.0)"] [[package]] name = "fastapi-sso" @@ -804,77 +936,163 @@ pydantic = {version = ">=1.8.0", extras = ["email"]} [[package]] name = "filelock" -version = "3.15.4" +version = "3.16.1" description = "A platform independent file lock." optional = false python-versions = ">=3.8" files = [ - {file = "filelock-3.15.4-py3-none-any.whl", hash = "sha256:6ca1fffae96225dab4c6eaf1c4f4f28cd2568d3ec2a44e15a08520504de468e7"}, - {file = "filelock-3.15.4.tar.gz", hash = "sha256:2207938cbc1844345cb01a5a95524dae30f0ce089eba5b00378295a17e3e90cb"}, + {file = "filelock-3.16.1-py3-none-any.whl", hash = "sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0"}, + {file = "filelock-3.16.1.tar.gz", hash = "sha256:c249fbfcd5db47e5e2d6d62198e565475ee65e4831e2561c8e313fa7eb961435"}, ] [package.extras] -docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8.0.1)", "pytest (>=7.4.3)", "pytest-asyncio (>=0.21)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)", "virtualenv (>=20.26.2)"] -typing = ["typing-extensions (>=4.8)"] +docs = ["furo (>=2024.8.6)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4.1)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.6.1)", "diff-cover (>=9.2)", "pytest (>=8.3.3)", "pytest-asyncio (>=0.24)", "pytest-cov (>=5)", "pytest-mock (>=3.14)", "pytest-timeout (>=2.3.1)", "virtualenv (>=20.26.4)"] +typing = ["typing-extensions (>=4.12.2)"] + +[[package]] +name = "greenlet" +version = "3.1.1" +description = "Lightweight in-process concurrent programming" +optional = false +python-versions = ">=3.7" +files = [ + {file = "greenlet-3.1.1-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:0bbae94a29c9e5c7e4a2b7f0aae5c17e8e90acbfd3bf6270eeba60c39fce3563"}, + {file = "greenlet-3.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fde093fb93f35ca72a556cf72c92ea3ebfda3d79fc35bb19fbe685853869a83"}, + {file = "greenlet-3.1.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:36b89d13c49216cadb828db8dfa6ce86bbbc476a82d3a6c397f0efae0525bdd0"}, + {file = "greenlet-3.1.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:94b6150a85e1b33b40b1464a3f9988dcc5251d6ed06842abff82e42632fac120"}, + {file = "greenlet-3.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93147c513fac16385d1036b7e5b102c7fbbdb163d556b791f0f11eada7ba65dc"}, + {file = "greenlet-3.1.1-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:da7a9bff22ce038e19bf62c4dd1ec8391062878710ded0a845bcf47cc0200617"}, + {file = "greenlet-3.1.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b2795058c23988728eec1f36a4e5e4ebad22f8320c85f3587b539b9ac84128d7"}, + {file = "greenlet-3.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ed10eac5830befbdd0c32f83e8aa6288361597550ba669b04c48f0f9a2c843c6"}, + {file = "greenlet-3.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:77c386de38a60d1dfb8e55b8c1101d68c79dfdd25c7095d51fec2dd800892b80"}, + {file = "greenlet-3.1.1-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:e4d333e558953648ca09d64f13e6d8f0523fa705f51cae3f03b5983489958c70"}, + {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09fc016b73c94e98e29af67ab7b9a879c307c6731a2c9da0db5a7d9b7edd1159"}, + {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d5e975ca70269d66d17dd995dafc06f1b06e8cb1ec1e9ed54c1d1e4a7c4cf26e"}, + {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b2813dc3de8c1ee3f924e4d4227999285fd335d1bcc0d2be6dc3f1f6a318ec1"}, + {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e347b3bfcf985a05e8c0b7d462ba6f15b1ee1c909e2dcad795e49e91b152c383"}, + {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9e8f8c9cb53cdac7ba9793c276acd90168f416b9ce36799b9b885790f8ad6c0a"}, + {file = "greenlet-3.1.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:62ee94988d6b4722ce0028644418d93a52429e977d742ca2ccbe1c4f4a792511"}, + {file = "greenlet-3.1.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1776fd7f989fc6b8d8c8cb8da1f6b82c5814957264d1f6cf818d475ec2bf6395"}, + {file = "greenlet-3.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:48ca08c771c268a768087b408658e216133aecd835c0ded47ce955381105ba39"}, + {file = "greenlet-3.1.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:4afe7ea89de619adc868e087b4d2359282058479d7cfb94970adf4b55284574d"}, + {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f406b22b7c9a9b4f8aa9d2ab13d6ae0ac3e85c9a809bd590ad53fed2bf70dc79"}, + {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c3a701fe5a9695b238503ce5bbe8218e03c3bcccf7e204e455e7462d770268aa"}, + {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2846930c65b47d70b9d178e89c7e1a69c95c1f68ea5aa0a58646b7a96df12441"}, + {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:99cfaa2110534e2cf3ba31a7abcac9d328d1d9f1b95beede58294a60348fba36"}, + {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1443279c19fca463fc33e65ef2a935a5b09bb90f978beab37729e1c3c6c25fe9"}, + {file = "greenlet-3.1.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b7cede291382a78f7bb5f04a529cb18e068dd29e0fb27376074b6d0317bf4dd0"}, + {file = "greenlet-3.1.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:23f20bb60ae298d7d8656c6ec6db134bca379ecefadb0b19ce6f19d1f232a942"}, + {file = "greenlet-3.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:7124e16b4c55d417577c2077be379514321916d5790fa287c9ed6f23bd2ffd01"}, + {file = "greenlet-3.1.1-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:05175c27cb459dcfc05d026c4232f9de8913ed006d42713cb8a5137bd49375f1"}, + {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:935e943ec47c4afab8965954bf49bfa639c05d4ccf9ef6e924188f762145c0ff"}, + {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:667a9706c970cb552ede35aee17339a18e8f2a87a51fba2ed39ceeeb1004798a"}, + {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b8a678974d1f3aa55f6cc34dc480169d58f2e6d8958895d68845fa4ab566509e"}, + {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:efc0f674aa41b92da8c49e0346318c6075d734994c3c4e4430b1c3f853e498e4"}, + {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0153404a4bb921f0ff1abeb5ce8a5131da56b953eda6e14b88dc6bbc04d2049e"}, + {file = "greenlet-3.1.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:275f72decf9932639c1c6dd1013a1bc266438eb32710016a1c742df5da6e60a1"}, + {file = "greenlet-3.1.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:c4aab7f6381f38a4b42f269057aee279ab0fc7bf2e929e3d4abfae97b682a12c"}, + {file = "greenlet-3.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:b42703b1cf69f2aa1df7d1030b9d77d3e584a70755674d60e710f0af570f3761"}, + {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f1695e76146579f8c06c1509c7ce4dfe0706f49c6831a817ac04eebb2fd02011"}, + {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7876452af029456b3f3549b696bb36a06db7c90747740c5302f74a9e9fa14b13"}, + {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4ead44c85f8ab905852d3de8d86f6f8baf77109f9da589cb4fa142bd3b57b475"}, + {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8320f64b777d00dd7ccdade271eaf0cad6636343293a25074cc5566160e4de7b"}, + {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6510bf84a6b643dabba74d3049ead221257603a253d0a9873f55f6a59a65f822"}, + {file = "greenlet-3.1.1-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:04b013dc07c96f83134b1e99888e7a79979f1a247e2a9f59697fa14b5862ed01"}, + {file = "greenlet-3.1.1-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:411f015496fec93c1c8cd4e5238da364e1da7a124bcb293f085bf2860c32c6f6"}, + {file = "greenlet-3.1.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:47da355d8687fd65240c364c90a31569a133b7b60de111c255ef5b606f2ae291"}, + {file = "greenlet-3.1.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:98884ecf2ffb7d7fe6bd517e8eb99d31ff7855a840fa6d0d63cd07c037f6a981"}, + {file = "greenlet-3.1.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f1d4aeb8891338e60d1ab6127af1fe45def5259def8094b9c7e34690c8858803"}, + {file = "greenlet-3.1.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db32b5348615a04b82240cc67983cb315309e88d444a288934ee6ceaebcad6cc"}, + {file = "greenlet-3.1.1-cp37-cp37m-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dcc62f31eae24de7f8dce72134c8651c58000d3b1868e01392baea7c32c247de"}, + {file = "greenlet-3.1.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:1d3755bcb2e02de341c55b4fca7a745a24a9e7212ac953f6b3a48d117d7257aa"}, + {file = "greenlet-3.1.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:b8da394b34370874b4572676f36acabac172602abf054cbc4ac910219f3340af"}, + {file = "greenlet-3.1.1-cp37-cp37m-win32.whl", hash = "sha256:a0dfc6c143b519113354e780a50381508139b07d2177cb6ad6a08278ec655798"}, + {file = "greenlet-3.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:54558ea205654b50c438029505def3834e80f0869a70fb15b871c29b4575ddef"}, + {file = "greenlet-3.1.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:346bed03fe47414091be4ad44786d1bd8bef0c3fcad6ed3dee074a032ab408a9"}, + {file = "greenlet-3.1.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dfc59d69fc48664bc693842bd57acfdd490acafda1ab52c7836e3fc75c90a111"}, + {file = "greenlet-3.1.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d21e10da6ec19b457b82636209cbe2331ff4306b54d06fa04b7c138ba18c8a81"}, + {file = "greenlet-3.1.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:37b9de5a96111fc15418819ab4c4432e4f3c2ede61e660b1e33971eba26ef9ba"}, + {file = "greenlet-3.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ef9ea3f137e5711f0dbe5f9263e8c009b7069d8a1acea822bd5e9dae0ae49c8"}, + {file = "greenlet-3.1.1-cp38-cp38-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:85f3ff71e2e60bd4b4932a043fbbe0f499e263c628390b285cb599154a3b03b1"}, + {file = "greenlet-3.1.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:95ffcf719966dd7c453f908e208e14cde192e09fde6c7186c8f1896ef778d8cd"}, + {file = "greenlet-3.1.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:03a088b9de532cbfe2ba2034b2b85e82df37874681e8c470d6fb2f8c04d7e4b7"}, + {file = "greenlet-3.1.1-cp38-cp38-win32.whl", hash = "sha256:8b8b36671f10ba80e159378df9c4f15c14098c4fd73a36b9ad715f057272fbef"}, + {file = "greenlet-3.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:7017b2be767b9d43cc31416aba48aab0d2309ee31b4dbf10a1d38fb7972bdf9d"}, + {file = "greenlet-3.1.1-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:396979749bd95f018296af156201d6211240e7a23090f50a8d5d18c370084dc3"}, + {file = "greenlet-3.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca9d0ff5ad43e785350894d97e13633a66e2b50000e8a183a50a88d834752d42"}, + {file = "greenlet-3.1.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f6ff3b14f2df4c41660a7dec01045a045653998784bf8cfcb5a525bdffffbc8f"}, + {file = "greenlet-3.1.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:94ebba31df2aa506d7b14866fed00ac141a867e63143fe5bca82a8e503b36437"}, + {file = "greenlet-3.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:73aaad12ac0ff500f62cebed98d8789198ea0e6f233421059fa68a5aa7220145"}, + {file = "greenlet-3.1.1-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:63e4844797b975b9af3a3fb8f7866ff08775f5426925e1e0bbcfe7932059a12c"}, + {file = "greenlet-3.1.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7939aa3ca7d2a1593596e7ac6d59391ff30281ef280d8632fa03d81f7c5f955e"}, + {file = "greenlet-3.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d0028e725ee18175c6e422797c407874da24381ce0690d6b9396c204c7f7276e"}, + {file = "greenlet-3.1.1-cp39-cp39-win32.whl", hash = "sha256:5e06afd14cbaf9e00899fae69b24a32f2196c19de08fcb9f4779dd4f004e5e7c"}, + {file = "greenlet-3.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:3319aa75e0e0639bc15ff54ca327e8dc7a6fe404003496e3c6925cd3142e0e22"}, + {file = "greenlet-3.1.1.tar.gz", hash = "sha256:4ce3ac6cdb6adf7946475d7ef31777c26d94bccc377e070a7986bd2d5c515467"}, +] + +[package.extras] +docs = ["Sphinx", "furo"] +test = ["objgraph", "psutil"] [[package]] name = "grpcio" -version = "1.65.5" +version = "1.66.1" description = "HTTP/2-based RPC framework" optional = false python-versions = ">=3.8" files = [ - {file = "grpcio-1.65.5-cp310-cp310-linux_armv7l.whl", hash = "sha256:b67d450f1e008fedcd81e097a3a400a711d8be1a8b20f852a7b8a73fead50fe3"}, - {file = "grpcio-1.65.5-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:a70a20eed87bba647a38bedd93b3ce7db64b3f0e8e0952315237f7f5ca97b02d"}, - {file = "grpcio-1.65.5-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:f79c87c114bf37adf408026b9e2e333fe9ff31dfc9648f6f80776c513145c813"}, - {file = "grpcio-1.65.5-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f17f9fa2d947dbfaca01b3ab2c62eefa8240131fdc67b924eb42ce6032e3e5c1"}, - {file = "grpcio-1.65.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:32d60e18ff7c34fe3f6db3d35ad5c6dc99f5b43ff3982cb26fad4174462d10b1"}, - {file = "grpcio-1.65.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:fe6505376f5b00bb008e4e1418152e3ad3d954b629da286c7913ff3cfc0ff740"}, - {file = "grpcio-1.65.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:33158e56c6378063923c417e9fbdb28660b6e0e2835af42e67f5a7793f587af7"}, - {file = "grpcio-1.65.5-cp310-cp310-win32.whl", hash = "sha256:1cbc208edb9acf1cc339396a1a36b83796939be52f34e591c90292045b579fbf"}, - {file = "grpcio-1.65.5-cp310-cp310-win_amd64.whl", hash = "sha256:bc74f3f745c37e2c5685c9d2a2d5a94de00f286963f5213f763ae137bf4f2358"}, - {file = "grpcio-1.65.5-cp311-cp311-linux_armv7l.whl", hash = "sha256:3207ae60d07e5282c134b6e02f9271a2cb523c6d7a346c6315211fe2bf8d61ed"}, - {file = "grpcio-1.65.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a2f80510f99f82d4eb825849c486df703f50652cea21c189eacc2b84f2bde764"}, - {file = "grpcio-1.65.5-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:a80e9a5e3f93c54f5eb82a3825ea1fc4965b2fa0026db2abfecb139a5c4ecdf1"}, - {file = "grpcio-1.65.5-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0b2944390a496567de9e70418f3742b477d85d8ca065afa90432edc91b4bb8ad"}, - {file = "grpcio-1.65.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c3655139d7be213c32c79ef6fb2367cae28e56ef68e39b1961c43214b457f257"}, - {file = "grpcio-1.65.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:05f02d68fc720e085f061b704ee653b181e6d5abfe315daef085719728d3d1fd"}, - {file = "grpcio-1.65.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1c4caafe71aef4dabf53274bbf4affd6df651e9f80beedd6b8e08ff438ed3260"}, - {file = "grpcio-1.65.5-cp311-cp311-win32.whl", hash = "sha256:84c901cdec16a092099f251ef3360d15e29ef59772150fa261d94573612539b5"}, - {file = "grpcio-1.65.5-cp311-cp311-win_amd64.whl", hash = "sha256:11f8b16121768c1cb99d7dcb84e01510e60e6a206bf9123e134118802486f035"}, - {file = "grpcio-1.65.5-cp312-cp312-linux_armv7l.whl", hash = "sha256:ee6ed64a27588a2c94e8fa84fe8f3b5c89427d4d69c37690903d428ec61ca7e4"}, - {file = "grpcio-1.65.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:76991b7a6fb98630a3328839755181ce7c1aa2b1842aa085fd4198f0e5198960"}, - {file = "grpcio-1.65.5-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:89c00a18801b1ed9cc441e29b521c354725d4af38c127981f2c950c796a09b6e"}, - {file = "grpcio-1.65.5-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:078038e150a897e5e402ed3d57f1d31ebf604cbed80f595bd281b5da40762a92"}, - {file = "grpcio-1.65.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c97962720489ef31b5ad8a916e22bc31bba3664e063fb9f6702dce056d4aa61b"}, - {file = "grpcio-1.65.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:b8270b15b99781461b244f5c81d5c2bc9696ab9189fb5ff86c841417fb3b39fe"}, - {file = "grpcio-1.65.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8e5c4c15ac3fe1eb68e46bc51e66ad29be887479f231f8237cf8416058bf0cc1"}, - {file = "grpcio-1.65.5-cp312-cp312-win32.whl", hash = "sha256:f5b5970341359341d0e4c789da7568264b2a89cd976c05ea476036852b5950cd"}, - {file = "grpcio-1.65.5-cp312-cp312-win_amd64.whl", hash = "sha256:238a625f391a1b9f5f069bdc5930f4fd71b74426bea52196fc7b83f51fa97d34"}, - {file = "grpcio-1.65.5-cp38-cp38-linux_armv7l.whl", hash = "sha256:6c4e62bcf297a1568f627f39576dbfc27f1e5338a691c6dd5dd6b3979da51d1c"}, - {file = "grpcio-1.65.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:d7df567b67d16d4177835a68d3f767bbcbad04da9dfb52cbd19171f430c898bd"}, - {file = "grpcio-1.65.5-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:b7ca419f1462390851eec395b2089aad1e49546b52d4e2c972ceb76da69b10f8"}, - {file = "grpcio-1.65.5-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fa36dd8496d3af0d40165252a669fa4f6fd2db4b4026b9a9411cbf060b9d6a15"}, - {file = "grpcio-1.65.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a101696f9ece90a0829988ff72f1b1ea2358f3df035bdf6d675dd8b60c2c0894"}, - {file = "grpcio-1.65.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:2a6d8169812932feac514b420daffae8ab8e36f90f3122b94ae767e633296b17"}, - {file = "grpcio-1.65.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:47d0aaaab82823f0aa6adea5184350b46e2252e13a42a942db84da5b733f2e05"}, - {file = "grpcio-1.65.5-cp38-cp38-win32.whl", hash = "sha256:85ae8f8517d5bcc21fb07dbf791e94ed84cc28f84c903cdc2bd7eaeb437c8f45"}, - {file = "grpcio-1.65.5-cp38-cp38-win_amd64.whl", hash = "sha256:770bd4bd721961f6dd8049bc27338564ba8739913f77c0f381a9815e465ff965"}, - {file = "grpcio-1.65.5-cp39-cp39-linux_armv7l.whl", hash = "sha256:ab5ec837d8cee8dbce9ef6386125f119b231e4333cc6b6d57b6c5c7c82a72331"}, - {file = "grpcio-1.65.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:cabd706183ee08d8026a015af5819a0b3a8959bdc9d1f6fdacd1810f09200f2a"}, - {file = "grpcio-1.65.5-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:ec71fc5b39821ad7d80db7473c8f8c2910f3382f0ddadfbcfc2c6c437107eb67"}, - {file = "grpcio-1.65.5-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d3a9e35bcb045e39d7cac30464c285389b9a816ac2067e4884ad2c02e709ef8e"}, - {file = "grpcio-1.65.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d750e9330eb14236ca11b78d0c494eed13d6a95eb55472298f0e547c165ee324"}, - {file = "grpcio-1.65.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:2b91ce647b6307f25650872454a4d02a2801f26a475f90d0b91ed8110baae589"}, - {file = "grpcio-1.65.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8da58ff80bc4556cf29bc03f5fff1f03b8387d6aaa7b852af9eb65b2cf833be4"}, - {file = "grpcio-1.65.5-cp39-cp39-win32.whl", hash = "sha256:7a412959aa5f08c5ac04aa7b7c3c041f5e4298cadd4fcc2acff195b56d185ebc"}, - {file = "grpcio-1.65.5-cp39-cp39-win_amd64.whl", hash = "sha256:55714ea852396ec9568f45f487639945ab674de83c12bea19d5ddbc3ae41ada3"}, - {file = "grpcio-1.65.5.tar.gz", hash = "sha256:ec6f219fb5d677a522b0deaf43cea6697b16f338cb68d009e30930c4aa0d2209"}, + {file = "grpcio-1.66.1-cp310-cp310-linux_armv7l.whl", hash = "sha256:4877ba180591acdf127afe21ec1c7ff8a5ecf0fe2600f0d3c50e8c4a1cbc6492"}, + {file = "grpcio-1.66.1-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:3750c5a00bd644c75f4507f77a804d0189d97a107eb1481945a0cf3af3e7a5ac"}, + {file = "grpcio-1.66.1-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:a013c5fbb12bfb5f927444b477a26f1080755a931d5d362e6a9a720ca7dbae60"}, + {file = "grpcio-1.66.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b1b24c23d51a1e8790b25514157d43f0a4dce1ac12b3f0b8e9f66a5e2c4c132f"}, + {file = "grpcio-1.66.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b7ffb8ea674d68de4cac6f57d2498fef477cef582f1fa849e9f844863af50083"}, + {file = "grpcio-1.66.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:307b1d538140f19ccbd3aed7a93d8f71103c5d525f3c96f8616111614b14bf2a"}, + {file = "grpcio-1.66.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1c17ebcec157cfb8dd445890a03e20caf6209a5bd4ac5b040ae9dbc59eef091d"}, + {file = "grpcio-1.66.1-cp310-cp310-win32.whl", hash = "sha256:ef82d361ed5849d34cf09105d00b94b6728d289d6b9235513cb2fcc79f7c432c"}, + {file = "grpcio-1.66.1-cp310-cp310-win_amd64.whl", hash = "sha256:292a846b92cdcd40ecca46e694997dd6b9be6c4c01a94a0dfb3fcb75d20da858"}, + {file = "grpcio-1.66.1-cp311-cp311-linux_armv7l.whl", hash = "sha256:c30aeceeaff11cd5ddbc348f37c58bcb96da8d5aa93fed78ab329de5f37a0d7a"}, + {file = "grpcio-1.66.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8a1e224ce6f740dbb6b24c58f885422deebd7eb724aff0671a847f8951857c26"}, + {file = "grpcio-1.66.1-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:a66fe4dc35d2330c185cfbb42959f57ad36f257e0cc4557d11d9f0a3f14311df"}, + {file = "grpcio-1.66.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e3ba04659e4fce609de2658fe4dbf7d6ed21987a94460f5f92df7579fd5d0e22"}, + {file = "grpcio-1.66.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4573608e23f7e091acfbe3e84ac2045680b69751d8d67685ffa193a4429fedb1"}, + {file = "grpcio-1.66.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:7e06aa1f764ec8265b19d8f00140b8c4b6ca179a6dc67aa9413867c47e1fb04e"}, + {file = "grpcio-1.66.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3885f037eb11f1cacc41f207b705f38a44b69478086f40608959bf5ad85826dd"}, + {file = "grpcio-1.66.1-cp311-cp311-win32.whl", hash = "sha256:97ae7edd3f3f91480e48ede5d3e7d431ad6005bfdbd65c1b56913799ec79e791"}, + {file = "grpcio-1.66.1-cp311-cp311-win_amd64.whl", hash = "sha256:cfd349de4158d797db2bd82d2020554a121674e98fbe6b15328456b3bf2495bb"}, + {file = "grpcio-1.66.1-cp312-cp312-linux_armv7l.whl", hash = "sha256:a92c4f58c01c77205df6ff999faa008540475c39b835277fb8883b11cada127a"}, + {file = "grpcio-1.66.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:fdb14bad0835914f325349ed34a51940bc2ad965142eb3090081593c6e347be9"}, + {file = "grpcio-1.66.1-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:f03a5884c56256e08fd9e262e11b5cfacf1af96e2ce78dc095d2c41ccae2c80d"}, + {file = "grpcio-1.66.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2ca2559692d8e7e245d456877a85ee41525f3ed425aa97eb7a70fc9a79df91a0"}, + {file = "grpcio-1.66.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:84ca1be089fb4446490dd1135828bd42a7c7f8421e74fa581611f7afdf7ab761"}, + {file = "grpcio-1.66.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:d639c939ad7c440c7b2819a28d559179a4508783f7e5b991166f8d7a34b52815"}, + {file = "grpcio-1.66.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:b9feb4e5ec8dc2d15709f4d5fc367794d69277f5d680baf1910fc9915c633524"}, + {file = "grpcio-1.66.1-cp312-cp312-win32.whl", hash = "sha256:7101db1bd4cd9b880294dec41a93fcdce465bdbb602cd8dc5bd2d6362b618759"}, + {file = "grpcio-1.66.1-cp312-cp312-win_amd64.whl", hash = "sha256:b0aa03d240b5539648d996cc60438f128c7f46050989e35b25f5c18286c86734"}, + {file = "grpcio-1.66.1-cp38-cp38-linux_armv7l.whl", hash = "sha256:ecfe735e7a59e5a98208447293ff8580e9db1e890e232b8b292dc8bd15afc0d2"}, + {file = "grpcio-1.66.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:4825a3aa5648010842e1c9d35a082187746aa0cdbf1b7a2a930595a94fb10fce"}, + {file = "grpcio-1.66.1-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:f517fd7259fe823ef3bd21e508b653d5492e706e9f0ef82c16ce3347a8a5620c"}, + {file = "grpcio-1.66.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f1fe60d0772831d96d263b53d83fb9a3d050a94b0e94b6d004a5ad111faa5b5b"}, + {file = "grpcio-1.66.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31a049daa428f928f21090403e5d18ea02670e3d5d172581670be006100db9ef"}, + {file = "grpcio-1.66.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:6f914386e52cbdeb5d2a7ce3bf1fdfacbe9d818dd81b6099a05b741aaf3848bb"}, + {file = "grpcio-1.66.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:bff2096bdba686019fb32d2dde45b95981f0d1490e054400f70fc9a8af34b49d"}, + {file = "grpcio-1.66.1-cp38-cp38-win32.whl", hash = "sha256:aa8ba945c96e73de29d25331b26f3e416e0c0f621e984a3ebdb2d0d0b596a3b3"}, + {file = "grpcio-1.66.1-cp38-cp38-win_amd64.whl", hash = "sha256:161d5c535c2bdf61b95080e7f0f017a1dfcb812bf54093e71e5562b16225b4ce"}, + {file = "grpcio-1.66.1-cp39-cp39-linux_armv7l.whl", hash = "sha256:d0cd7050397b3609ea51727b1811e663ffda8bda39c6a5bb69525ef12414b503"}, + {file = "grpcio-1.66.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:0e6c9b42ded5d02b6b1fea3a25f036a2236eeb75d0579bfd43c0018c88bf0a3e"}, + {file = "grpcio-1.66.1-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:c9f80f9fad93a8cf71c7f161778ba47fd730d13a343a46258065c4deb4b550c0"}, + {file = "grpcio-1.66.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5dd67ed9da78e5121efc5c510f0122a972216808d6de70953a740560c572eb44"}, + {file = "grpcio-1.66.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:48b0d92d45ce3be2084b92fb5bae2f64c208fea8ceed7fccf6a7b524d3c4942e"}, + {file = "grpcio-1.66.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:4d813316d1a752be6f5c4360c49f55b06d4fe212d7df03253dfdae90c8a402bb"}, + {file = "grpcio-1.66.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9c9bebc6627873ec27a70fc800f6083a13c70b23a5564788754b9ee52c5aef6c"}, + {file = "grpcio-1.66.1-cp39-cp39-win32.whl", hash = "sha256:30a1c2cf9390c894c90bbc70147f2372130ad189cffef161f0432d0157973f45"}, + {file = "grpcio-1.66.1-cp39-cp39-win_amd64.whl", hash = "sha256:17663598aadbedc3cacd7bbde432f541c8e07d2496564e22b214b22c7523dac8"}, + {file = "grpcio-1.66.1.tar.gz", hash = "sha256:35334f9c9745add3e357e3372756fd32d925bd52c41da97f4dfdafbde0bf0ee2"}, ] [package.extras] -protobuf = ["grpcio-tools (>=1.65.5)"] +protobuf = ["grpcio-tools (>=1.66.1)"] [[package]] name = "h11" @@ -889,12 +1107,12 @@ files = [ [[package]] name = "http-ece" -version = "1.2.0" +version = "1.2.1" description = "Encrypted Content Encoding for HTTP" optional = false python-versions = "*" files = [ - {file = "http_ece-1.2.0.tar.gz", hash = "sha256:b5920f8efb8e1b5fb025713e3b36fda54336262010634b26dc1f98f85d1eb3de"}, + {file = "http_ece-1.2.1.tar.gz", hash = "sha256:8c6ab23116bbf6affda894acfd5f2ca0fb8facbcbb72121c11c75c33e7ce8cff"}, ] [package.dependencies] @@ -902,13 +1120,13 @@ cryptography = ">=2.5" [[package]] name = "httpcore" -version = "1.0.5" +version = "1.0.7" description = "A minimal low-level HTTP client." optional = false python-versions = ">=3.8" files = [ - {file = "httpcore-1.0.5-py3-none-any.whl", hash = "sha256:421f18bac248b25d310f3cacd198d55b8e6125c107797b609ff9b7a6ba7991b5"}, - {file = "httpcore-1.0.5.tar.gz", hash = "sha256:34a38e2f9291467ee3b44e89dd52615370e152954ba21721378a87b2960f7a61"}, + {file = "httpcore-1.0.7-py3-none-any.whl", hash = "sha256:a3fff8f43dc260d5bd363d9f9cf1830fa3a458b332856f34282de498ed420edd"}, + {file = "httpcore-1.0.7.tar.gz", hash = "sha256:8551cb62a169ec7162ac7be8d4817d561f60e08eaa485234898414bb5a8a0b4c"}, ] [package.dependencies] @@ -919,7 +1137,7 @@ h11 = ">=0.13,<0.15" asyncio = ["anyio (>=4.0,<5.0)"] http2 = ["h2 (>=3,<5)"] socks = ["socksio (==1.*)"] -trio = ["trio (>=0.22.0,<0.26.0)"] +trio = ["trio (>=0.22.0,<1.0)"] [[package]] name = "httpx" @@ -947,13 +1165,13 @@ socks = ["socksio (==1.*)"] [[package]] name = "identify" -version = "2.6.0" +version = "2.6.2" description = "File identification library for Python" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "identify-2.6.0-py2.py3-none-any.whl", hash = "sha256:e79ae4406387a9d300332b5fd366d8994f1525e8414984e1a59e058b2eda2dd0"}, - {file = "identify-2.6.0.tar.gz", hash = "sha256:cb171c685bdc31bcc4c1734698736a7d5b6c8bf2e0c15117f4d469c8640ae5cf"}, + {file = "identify-2.6.2-py2.py3-none-any.whl", hash = "sha256:c097384259f49e372f4ea00a19719d95ae27dd5ff0fd77ad630aa891306b82f3"}, + {file = "identify-2.6.2.tar.gz", hash = "sha256:fab5c716c24d7a789775228823797296a2994b075fb6080ac83a102772a98cbd"}, ] [package.extras] @@ -961,32 +1179,39 @@ license = ["ukkonen"] [[package]] name = "idna" -version = "3.7" +version = "3.10" description = "Internationalized Domain Names in Applications (IDNA)" optional = false -python-versions = ">=3.5" +python-versions = ">=3.6" files = [ - {file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"}, - {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"}, + {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, + {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, ] +[package.extras] +all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] + [[package]] name = "importlib-resources" -version = "6.4.0" +version = "6.4.5" description = "Read resources from Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "importlib_resources-6.4.0-py3-none-any.whl", hash = "sha256:50d10f043df931902d4194ea07ec57960f66a80449ff867bfe782b4c486ba78c"}, - {file = "importlib_resources-6.4.0.tar.gz", hash = "sha256:cdb2b453b8046ca4e3798eb1d84f3cce1446a0e8e7b5ef4efb600f19fc398145"}, + {file = "importlib_resources-6.4.5-py3-none-any.whl", hash = "sha256:ac29d5f956f01d5e4bb63102a5a19957f1b9175e45649977264a1416783bb717"}, + {file = "importlib_resources-6.4.5.tar.gz", hash = "sha256:980862a1d16c9e147a59603677fa2aa5fd82b87f223b6cb870695bcfce830065"}, ] [package.dependencies] zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""} [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["jaraco.test (>=5.4)", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)", "zipp (>=3.17)"] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +enabler = ["pytest-enabler (>=2.2)"] +test = ["jaraco.test (>=5.4)", "pytest (>=6,!=8.1.*)", "zipp (>=3.17)"] +type = ["pytest-mypy"] [[package]] name = "iniconfig" @@ -1058,16 +1283,18 @@ rediscluster = ["redis (>=4.2.0,!=4.5.2,!=4.5.3)"] [[package]] name = "lnbits" -version = "0.12.11" +version = "1.0.0rc5" description = "LNbits, free and open-source Lightning wallet and accounts system." optional = false python-versions = "<4.0,>=3.9" files = [ - {file = "lnbits-0.12.11-py3-none-any.whl", hash = "sha256:269c38aa1f88085cf3d00c4427dab7f2ced0e08692a2b2ea77d5a181fa9d170a"}, - {file = "lnbits-0.12.11.tar.gz", hash = "sha256:5137d3d8ef4d4a3d1f961b8fdd8644f69ec2c440b06adac6a0c0e7161b2e4e01"}, + {file = "lnbits-1.0.0rc5-py3-none-any.whl", hash = "sha256:3107a9c6711720299add7880b62c020cbf34cee2486d47f2c3ddd3f6b4a76b9d"}, + {file = "lnbits-1.0.0rc5.tar.gz", hash = "sha256:f5559efa5d9b81f89acc1510db052d6300b3e93e1d0acdc70204689501865a51"}, ] [package.dependencies] +aiosqlite = "0.20.0" +asyncpg = "0.29.0" bcrypt = "4.2.0" bech32 = "1.2.0" bolt11 = "2.1.0" @@ -1075,9 +1302,9 @@ click = "8.1.7" ecdsa = "0.19.0" embit = "0.8.0" environs = "9.5.0" -fastapi = "0.112.0" +fastapi = "0.115.2" fastapi-sso = "0.15.0" -grpcio = "1.65.5" +grpcio = "1.66.1" httpx = "0.27.0" itsdangerous = "2.2.0" jinja2 = "3.1.4" @@ -1085,23 +1312,21 @@ lnurl = "0.5.3" loguru = "0.7.2" packaging = "24.0" passlib = "1.7.4" -protobuf = "5.27.3" -psycopg2-binary = "2.9.9" +protobuf = "5.28.0" pycryptodomex = "3.20.0" -pydantic = "1.10.17" +pydantic = "1.10.18" pyjwt = "2.9.0" -pyln-client = "24.5" +pyln-client = "24.8.1" pyqrcode = "1.2.1" python-crontab = "3.2.0" pywebpush = "1.14.1" secp256k1 = "0.14.0" shortuuid = "1.0.13" slowapi = "0.1.9" -sqlalchemy = "1.3.24" -sqlalchemy-aio = "0.17.0" +sqlalchemy = "1.4.54" sse-starlette = "1.8.2" typing-extensions = "4.12.2" -uvicorn = "0.30.5" +uvicorn = "0.30.6" uvloop = "0.19.0" websocket-client = "1.8.0" websockets = "11.0.3" @@ -1148,135 +1373,142 @@ dev = ["Sphinx (==7.2.5)", "colorama (==0.4.5)", "colorama (==0.4.6)", "exceptio [[package]] name = "markupsafe" -version = "2.1.5" +version = "3.0.2" description = "Safely add untrusted strings to HTML/XML markup." optional = false -python-versions = ">=3.7" +python-versions = ">=3.9" files = [ - {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-win32.whl", hash = "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-win_amd64.whl", hash = "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-win32.whl", hash = "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-win_amd64.whl", hash = "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-win32.whl", hash = "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5"}, - {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-win32.whl", hash = "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-win32.whl", hash = "sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a"}, + {file = "markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0"}, ] [[package]] name = "marshmallow" -version = "3.21.3" +version = "3.23.1" description = "A lightweight library for converting complex datatypes to and from native Python datatypes." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "marshmallow-3.21.3-py3-none-any.whl", hash = "sha256:86ce7fb914aa865001a4b2092c4c2872d13bc347f3d42673272cabfdbad386f1"}, - {file = "marshmallow-3.21.3.tar.gz", hash = "sha256:4f57c5e050a54d66361e826f94fba213eb10b67b2fdb02c3e0343ce207ba1662"}, + {file = "marshmallow-3.23.1-py3-none-any.whl", hash = "sha256:fece2eb2c941180ea1b7fcbd4a83c51bfdd50093fdd3ad2585ee5e1df2508491"}, + {file = "marshmallow-3.23.1.tar.gz", hash = "sha256:3a8dfda6edd8dcdbf216c0ede1d1e78d230a6dc9c5a088f58c4083b974a0d468"}, ] [package.dependencies] packaging = ">=17.0" [package.extras] -dev = ["marshmallow[tests]", "pre-commit (>=3.5,<4.0)", "tox"] -docs = ["alabaster (==0.7.16)", "autodocsumm (==0.2.12)", "sphinx (==7.3.7)", "sphinx-issues (==4.1.0)", "sphinx-version-warning (==1.1.2)"] -tests = ["pytest", "pytz", "simplejson"] +dev = ["marshmallow[tests]", "pre-commit (>=3.5,<5.0)", "tox"] +docs = ["alabaster (==1.0.0)", "autodocsumm (==0.2.14)", "sphinx (==8.1.3)", "sphinx-issues (==5.0.0)", "sphinx-version-warning (==1.1.2)"] +tests = ["pytest", "simplejson"] [[package]] name = "mypy" -version = "1.10.1" +version = "1.13.0" description = "Optional static typing for Python" optional = false python-versions = ">=3.8" files = [ - {file = "mypy-1.10.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e36f229acfe250dc660790840916eb49726c928e8ce10fbdf90715090fe4ae02"}, - {file = "mypy-1.10.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:51a46974340baaa4145363b9e051812a2446cf583dfaeba124af966fa44593f7"}, - {file = "mypy-1.10.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:901c89c2d67bba57aaaca91ccdb659aa3a312de67f23b9dfb059727cce2e2e0a"}, - {file = "mypy-1.10.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0cd62192a4a32b77ceb31272d9e74d23cd88c8060c34d1d3622db3267679a5d9"}, - {file = "mypy-1.10.1-cp310-cp310-win_amd64.whl", hash = "sha256:a2cbc68cb9e943ac0814c13e2452d2046c2f2b23ff0278e26599224cf164e78d"}, - {file = "mypy-1.10.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:bd6f629b67bb43dc0d9211ee98b96d8dabc97b1ad38b9b25f5e4c4d7569a0c6a"}, - {file = "mypy-1.10.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a1bbb3a6f5ff319d2b9d40b4080d46cd639abe3516d5a62c070cf0114a457d84"}, - {file = "mypy-1.10.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8edd4e9bbbc9d7b79502eb9592cab808585516ae1bcc1446eb9122656c6066f"}, - {file = "mypy-1.10.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6166a88b15f1759f94a46fa474c7b1b05d134b1b61fca627dd7335454cc9aa6b"}, - {file = "mypy-1.10.1-cp311-cp311-win_amd64.whl", hash = "sha256:5bb9cd11c01c8606a9d0b83ffa91d0b236a0e91bc4126d9ba9ce62906ada868e"}, - {file = "mypy-1.10.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d8681909f7b44d0b7b86e653ca152d6dff0eb5eb41694e163c6092124f8246d7"}, - {file = "mypy-1.10.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:378c03f53f10bbdd55ca94e46ec3ba255279706a6aacaecac52ad248f98205d3"}, - {file = "mypy-1.10.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6bacf8f3a3d7d849f40ca6caea5c055122efe70e81480c8328ad29c55c69e93e"}, - {file = "mypy-1.10.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:701b5f71413f1e9855566a34d6e9d12624e9e0a8818a5704d74d6b0402e66c04"}, - {file = "mypy-1.10.1-cp312-cp312-win_amd64.whl", hash = "sha256:3c4c2992f6ea46ff7fce0072642cfb62af7a2484efe69017ed8b095f7b39ef31"}, - {file = "mypy-1.10.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:604282c886497645ffb87b8f35a57ec773a4a2721161e709a4422c1636ddde5c"}, - {file = "mypy-1.10.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37fd87cab83f09842653f08de066ee68f1182b9b5282e4634cdb4b407266bade"}, - {file = "mypy-1.10.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8addf6313777dbb92e9564c5d32ec122bf2c6c39d683ea64de6a1fd98b90fe37"}, - {file = "mypy-1.10.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5cc3ca0a244eb9a5249c7c583ad9a7e881aa5d7b73c35652296ddcdb33b2b9c7"}, - {file = "mypy-1.10.1-cp38-cp38-win_amd64.whl", hash = "sha256:1b3a2ffce52cc4dbaeee4df762f20a2905aa171ef157b82192f2e2f368eec05d"}, - {file = "mypy-1.10.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fe85ed6836165d52ae8b88f99527d3d1b2362e0cb90b005409b8bed90e9059b3"}, - {file = "mypy-1.10.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c2ae450d60d7d020d67ab440c6e3fae375809988119817214440033f26ddf7bf"}, - {file = "mypy-1.10.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6be84c06e6abd72f960ba9a71561c14137a583093ffcf9bbfaf5e613d63fa531"}, - {file = "mypy-1.10.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2189ff1e39db399f08205e22a797383613ce1cb0cb3b13d8bcf0170e45b96cc3"}, - {file = "mypy-1.10.1-cp39-cp39-win_amd64.whl", hash = "sha256:97a131ee36ac37ce9581f4220311247ab6cba896b4395b9c87af0675a13a755f"}, - {file = "mypy-1.10.1-py3-none-any.whl", hash = "sha256:71d8ac0b906354ebda8ef1673e5fde785936ac1f29ff6987c7483cfbd5a4235a"}, - {file = "mypy-1.10.1.tar.gz", hash = "sha256:1f8f492d7db9e3593ef42d4f115f04e556130f2819ad33ab84551403e97dd4c0"}, + {file = "mypy-1.13.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6607e0f1dd1fb7f0aca14d936d13fd19eba5e17e1cd2a14f808fa5f8f6d8f60a"}, + {file = "mypy-1.13.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8a21be69bd26fa81b1f80a61ee7ab05b076c674d9b18fb56239d72e21d9f4c80"}, + {file = "mypy-1.13.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7b2353a44d2179846a096e25691d54d59904559f4232519d420d64da6828a3a7"}, + {file = "mypy-1.13.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0730d1c6a2739d4511dc4253f8274cdd140c55c32dfb0a4cf8b7a43f40abfa6f"}, + {file = "mypy-1.13.0-cp310-cp310-win_amd64.whl", hash = "sha256:c5fc54dbb712ff5e5a0fca797e6e0aa25726c7e72c6a5850cfd2adbc1eb0a372"}, + {file = "mypy-1.13.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:581665e6f3a8a9078f28d5502f4c334c0c8d802ef55ea0e7276a6e409bc0d82d"}, + {file = "mypy-1.13.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3ddb5b9bf82e05cc9a627e84707b528e5c7caaa1c55c69e175abb15a761cec2d"}, + {file = "mypy-1.13.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:20c7ee0bc0d5a9595c46f38beb04201f2620065a93755704e141fcac9f59db2b"}, + {file = "mypy-1.13.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3790ded76f0b34bc9c8ba4def8f919dd6a46db0f5a6610fb994fe8efdd447f73"}, + {file = "mypy-1.13.0-cp311-cp311-win_amd64.whl", hash = "sha256:51f869f4b6b538229c1d1bcc1dd7d119817206e2bc54e8e374b3dfa202defcca"}, + {file = "mypy-1.13.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5c7051a3461ae84dfb5dd15eff5094640c61c5f22257c8b766794e6dd85e72d5"}, + {file = "mypy-1.13.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:39bb21c69a5d6342f4ce526e4584bc5c197fd20a60d14a8624d8743fffb9472e"}, + {file = "mypy-1.13.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:164f28cb9d6367439031f4c81e84d3ccaa1e19232d9d05d37cb0bd880d3f93c2"}, + {file = "mypy-1.13.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a4c1bfcdbce96ff5d96fc9b08e3831acb30dc44ab02671eca5953eadad07d6d0"}, + {file = "mypy-1.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:a0affb3a79a256b4183ba09811e3577c5163ed06685e4d4b46429a271ba174d2"}, + {file = "mypy-1.13.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a7b44178c9760ce1a43f544e595d35ed61ac2c3de306599fa59b38a6048e1aa7"}, + {file = "mypy-1.13.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5d5092efb8516d08440e36626f0153b5006d4088c1d663d88bf79625af3d1d62"}, + {file = "mypy-1.13.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:de2904956dac40ced10931ac967ae63c5089bd498542194b436eb097a9f77bc8"}, + {file = "mypy-1.13.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:7bfd8836970d33c2105562650656b6846149374dc8ed77d98424b40b09340ba7"}, + {file = "mypy-1.13.0-cp313-cp313-win_amd64.whl", hash = "sha256:9f73dba9ec77acb86457a8fc04b5239822df0c14a082564737833d2963677dbc"}, + {file = "mypy-1.13.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:100fac22ce82925f676a734af0db922ecfea991e1d7ec0ceb1e115ebe501301a"}, + {file = "mypy-1.13.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7bcb0bb7f42a978bb323a7c88f1081d1b5dee77ca86f4100735a6f541299d8fb"}, + {file = "mypy-1.13.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bde31fc887c213e223bbfc34328070996061b0833b0a4cfec53745ed61f3519b"}, + {file = "mypy-1.13.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:07de989f89786f62b937851295ed62e51774722e5444a27cecca993fc3f9cd74"}, + {file = "mypy-1.13.0-cp38-cp38-win_amd64.whl", hash = "sha256:4bde84334fbe19bad704b3f5b78c4abd35ff1026f8ba72b29de70dda0916beb6"}, + {file = "mypy-1.13.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0246bcb1b5de7f08f2826451abd947bf656945209b140d16ed317f65a17dc7dc"}, + {file = "mypy-1.13.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7f5b7deae912cf8b77e990b9280f170381fdfbddf61b4ef80927edd813163732"}, + {file = "mypy-1.13.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7029881ec6ffb8bc233a4fa364736789582c738217b133f1b55967115288a2bc"}, + {file = "mypy-1.13.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3e38b980e5681f28f033f3be86b099a247b13c491f14bb8b1e1e134d23bb599d"}, + {file = "mypy-1.13.0-cp39-cp39-win_amd64.whl", hash = "sha256:a6789be98a2017c912ae6ccb77ea553bbaf13d27605d2ca20a76dfbced631b24"}, + {file = "mypy-1.13.0-py3-none-any.whl", hash = "sha256:9c250883f9fd81d212e0952c92dbfcc96fc237f4b7c92f56ac81fd48460b3e5a"}, + {file = "mypy-1.13.0.tar.gz", hash = "sha256:0291a61b6fbf3e6673e3405cfcc0e7650bebc7939659fdca2702958038bd835e"}, ] [package.dependencies] mypy-extensions = ">=1.0.0" tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} -typing-extensions = ">=4.1.0" +typing-extensions = ">=4.6.0" [package.extras] dmypy = ["psutil (>=4.0)"] +faster-cache = ["orjson"] install-types = ["pip"] mypyc = ["setuptools (>=50)"] reports = ["lxml"] @@ -1319,20 +1551,6 @@ rsa = ["cryptography (>=3.0.0)"] signals = ["blinker (>=1.4.0)"] signedtoken = ["cryptography (>=3.0.0)", "pyjwt (>=2.0.0,<3)"] -[[package]] -name = "outcome" -version = "1.3.0.post0" -description = "Capture the outcome of Python function calls." -optional = false -python-versions = ">=3.7" -files = [ - {file = "outcome-1.3.0.post0-py2.py3-none-any.whl", hash = "sha256:e771c5ce06d1415e356078d3bdd68523f284b4ce5419828922b6871e65eda82b"}, - {file = "outcome-1.3.0.post0.tar.gz", hash = "sha256:9dcf02e65f2971b80047b377468e72a268e15c0af3cf1238e6ff14f7f91143b8"}, -] - -[package.dependencies] -attrs = ">=19.2.0" - [[package]] name = "packaging" version = "24.0" @@ -1374,19 +1592,19 @@ files = [ [[package]] name = "platformdirs" -version = "4.2.2" +version = "4.3.6" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false python-versions = ">=3.8" files = [ - {file = "platformdirs-4.2.2-py3-none-any.whl", hash = "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee"}, - {file = "platformdirs-4.2.2.tar.gz", hash = "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3"}, + {file = "platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"}, + {file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"}, ] [package.extras] -docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"] -type = ["mypy (>=1.8)"] +docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.2)", "pytest-cov (>=5)", "pytest-mock (>=3.14)"] +type = ["mypy (>=1.11.2)"] [[package]] name = "pluggy" @@ -1405,13 +1623,13 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "pre-commit" -version = "3.7.1" +version = "3.8.0" description = "A framework for managing and maintaining multi-language pre-commit hooks." optional = false python-versions = ">=3.9" files = [ - {file = "pre_commit-3.7.1-py2.py3-none-any.whl", hash = "sha256:fae36fd1d7ad7d6a5a1c0b0d5adb2ed1a3bda5a21bf6c3e5372073d7a11cd4c5"}, - {file = "pre_commit-3.7.1.tar.gz", hash = "sha256:8ca3ad567bc78a4972a3f1a477e94a79d4597e8140a6e0b651c5e33899c3654a"}, + {file = "pre_commit-3.8.0-py2.py3-none-any.whl", hash = "sha256:9a90a53bf82fdd8778d58085faf8d83df56e40dfe18f45b19446e26bf1b3a63f"}, + {file = "pre_commit-3.8.0.tar.gz", hash = "sha256:8bb6494d4a20423842e198980c9ecf9f96607a07ea29549e180eef9ae80fe7af"}, ] [package.dependencies] @@ -1423,113 +1641,33 @@ virtualenv = ">=20.10.0" [[package]] name = "protobuf" -version = "5.27.3" +version = "5.28.0" description = "" optional = false python-versions = ">=3.8" files = [ - {file = "protobuf-5.27.3-cp310-abi3-win32.whl", hash = "sha256:dcb307cd4ef8fec0cf52cb9105a03d06fbb5275ce6d84a6ae33bc6cf84e0a07b"}, - {file = "protobuf-5.27.3-cp310-abi3-win_amd64.whl", hash = "sha256:16ddf3f8c6c41e1e803da7abea17b1793a97ef079a912e42351eabb19b2cffe7"}, - {file = "protobuf-5.27.3-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:68248c60d53f6168f565a8c76dc58ba4fa2ade31c2d1ebdae6d80f969cdc2d4f"}, - {file = "protobuf-5.27.3-cp38-abi3-manylinux2014_aarch64.whl", hash = "sha256:b8a994fb3d1c11156e7d1e427186662b64694a62b55936b2b9348f0a7c6625ce"}, - {file = "protobuf-5.27.3-cp38-abi3-manylinux2014_x86_64.whl", hash = "sha256:a55c48f2a2092d8e213bd143474df33a6ae751b781dd1d1f4d953c128a415b25"}, - {file = "protobuf-5.27.3-cp38-cp38-win32.whl", hash = "sha256:043853dcb55cc262bf2e116215ad43fa0859caab79bb0b2d31b708f128ece035"}, - {file = "protobuf-5.27.3-cp38-cp38-win_amd64.whl", hash = "sha256:c2a105c24f08b1e53d6c7ffe69cb09d0031512f0b72f812dd4005b8112dbe91e"}, - {file = "protobuf-5.27.3-cp39-cp39-win32.whl", hash = "sha256:c84eee2c71ed83704f1afbf1a85c3171eab0fd1ade3b399b3fad0884cbcca8bf"}, - {file = "protobuf-5.27.3-cp39-cp39-win_amd64.whl", hash = "sha256:af7c0b7cfbbb649ad26132e53faa348580f844d9ca46fd3ec7ca48a1ea5db8a1"}, - {file = "protobuf-5.27.3-py3-none-any.whl", hash = "sha256:8572c6533e544ebf6899c360e91d6bcbbee2549251643d32c52cf8a5de295ba5"}, - {file = "protobuf-5.27.3.tar.gz", hash = "sha256:82460903e640f2b7e34ee81a947fdaad89de796d324bcbc38ff5430bcdead82c"}, -] - -[[package]] -name = "psycopg2-binary" -version = "2.9.9" -description = "psycopg2 - Python-PostgreSQL Database Adapter" -optional = false -python-versions = ">=3.7" -files = [ - {file = "psycopg2-binary-2.9.9.tar.gz", hash = "sha256:7f01846810177d829c7692f1f5ada8096762d9172af1b1a28d4ab5b77c923c1c"}, - {file = "psycopg2_binary-2.9.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c2470da5418b76232f02a2fcd2229537bb2d5a7096674ce61859c3229f2eb202"}, - {file = "psycopg2_binary-2.9.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c6af2a6d4b7ee9615cbb162b0738f6e1fd1f5c3eda7e5da17861eacf4c717ea7"}, - {file = "psycopg2_binary-2.9.9-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:75723c3c0fbbf34350b46a3199eb50638ab22a0228f93fb472ef4d9becc2382b"}, - {file = "psycopg2_binary-2.9.9-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:83791a65b51ad6ee6cf0845634859d69a038ea9b03d7b26e703f94c7e93dbcf9"}, - {file = "psycopg2_binary-2.9.9-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0ef4854e82c09e84cc63084a9e4ccd6d9b154f1dbdd283efb92ecd0b5e2b8c84"}, - {file = "psycopg2_binary-2.9.9-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed1184ab8f113e8d660ce49a56390ca181f2981066acc27cf637d5c1e10ce46e"}, - {file = "psycopg2_binary-2.9.9-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d2997c458c690ec2bc6b0b7ecbafd02b029b7b4283078d3b32a852a7ce3ddd98"}, - {file = "psycopg2_binary-2.9.9-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:b58b4710c7f4161b5e9dcbe73bb7c62d65670a87df7bcce9e1faaad43e715245"}, - {file = "psycopg2_binary-2.9.9-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:0c009475ee389757e6e34611d75f6e4f05f0cf5ebb76c6037508318e1a1e0d7e"}, - {file = "psycopg2_binary-2.9.9-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8dbf6d1bc73f1d04ec1734bae3b4fb0ee3cb2a493d35ede9badbeb901fb40f6f"}, - {file = "psycopg2_binary-2.9.9-cp310-cp310-win32.whl", hash = "sha256:3f78fd71c4f43a13d342be74ebbc0666fe1f555b8837eb113cb7416856c79682"}, - {file = "psycopg2_binary-2.9.9-cp310-cp310-win_amd64.whl", hash = "sha256:876801744b0dee379e4e3c38b76fc89f88834bb15bf92ee07d94acd06ec890a0"}, - {file = "psycopg2_binary-2.9.9-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ee825e70b1a209475622f7f7b776785bd68f34af6e7a46e2e42f27b659b5bc26"}, - {file = "psycopg2_binary-2.9.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1ea665f8ce695bcc37a90ee52de7a7980be5161375d42a0b6c6abedbf0d81f0f"}, - {file = "psycopg2_binary-2.9.9-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:143072318f793f53819048fdfe30c321890af0c3ec7cb1dfc9cc87aa88241de2"}, - {file = "psycopg2_binary-2.9.9-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c332c8d69fb64979ebf76613c66b985414927a40f8defa16cf1bc028b7b0a7b0"}, - {file = "psycopg2_binary-2.9.9-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7fc5a5acafb7d6ccca13bfa8c90f8c51f13d8fb87d95656d3950f0158d3ce53"}, - {file = "psycopg2_binary-2.9.9-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:977646e05232579d2e7b9c59e21dbe5261f403a88417f6a6512e70d3f8a046be"}, - {file = "psycopg2_binary-2.9.9-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b6356793b84728d9d50ead16ab43c187673831e9d4019013f1402c41b1db9b27"}, - {file = "psycopg2_binary-2.9.9-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:bc7bb56d04601d443f24094e9e31ae6deec9ccb23581f75343feebaf30423359"}, - {file = "psycopg2_binary-2.9.9-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:77853062a2c45be16fd6b8d6de2a99278ee1d985a7bd8b103e97e41c034006d2"}, - {file = "psycopg2_binary-2.9.9-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:78151aa3ec21dccd5cdef6c74c3e73386dcdfaf19bced944169697d7ac7482fc"}, - {file = "psycopg2_binary-2.9.9-cp311-cp311-win32.whl", hash = "sha256:dc4926288b2a3e9fd7b50dc6a1909a13bbdadfc67d93f3374d984e56f885579d"}, - {file = "psycopg2_binary-2.9.9-cp311-cp311-win_amd64.whl", hash = "sha256:b76bedd166805480ab069612119ea636f5ab8f8771e640ae103e05a4aae3e417"}, - {file = "psycopg2_binary-2.9.9-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:8532fd6e6e2dc57bcb3bc90b079c60de896d2128c5d9d6f24a63875a95a088cf"}, - {file = "psycopg2_binary-2.9.9-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b0605eaed3eb239e87df0d5e3c6489daae3f7388d455d0c0b4df899519c6a38d"}, - {file = "psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f8544b092a29a6ddd72f3556a9fcf249ec412e10ad28be6a0c0d948924f2212"}, - {file = "psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2d423c8d8a3c82d08fe8af900ad5b613ce3632a1249fd6a223941d0735fce493"}, - {file = "psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2e5afae772c00980525f6d6ecf7cbca55676296b580c0e6abb407f15f3706996"}, - {file = "psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e6f98446430fdf41bd36d4faa6cb409f5140c1c2cf58ce0bbdaf16af7d3f119"}, - {file = "psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c77e3d1862452565875eb31bdb45ac62502feabbd53429fdc39a1cc341d681ba"}, - {file = "psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:cb16c65dcb648d0a43a2521f2f0a2300f40639f6f8c1ecbc662141e4e3e1ee07"}, - {file = "psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:911dda9c487075abd54e644ccdf5e5c16773470a6a5d3826fda76699410066fb"}, - {file = "psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:57fede879f08d23c85140a360c6a77709113efd1c993923c59fde17aa27599fe"}, - {file = "psycopg2_binary-2.9.9-cp312-cp312-win32.whl", hash = "sha256:64cf30263844fa208851ebb13b0732ce674d8ec6a0c86a4e160495d299ba3c93"}, - {file = "psycopg2_binary-2.9.9-cp312-cp312-win_amd64.whl", hash = "sha256:81ff62668af011f9a48787564ab7eded4e9fb17a4a6a74af5ffa6a457400d2ab"}, - {file = "psycopg2_binary-2.9.9-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2293b001e319ab0d869d660a704942c9e2cce19745262a8aba2115ef41a0a42a"}, - {file = "psycopg2_binary-2.9.9-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:03ef7df18daf2c4c07e2695e8cfd5ee7f748a1d54d802330985a78d2a5a6dca9"}, - {file = "psycopg2_binary-2.9.9-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a602ea5aff39bb9fac6308e9c9d82b9a35c2bf288e184a816002c9fae930b77"}, - {file = "psycopg2_binary-2.9.9-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8359bf4791968c5a78c56103702000105501adb557f3cf772b2c207284273984"}, - {file = "psycopg2_binary-2.9.9-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:275ff571376626195ab95a746e6a04c7df8ea34638b99fc11160de91f2fef503"}, - {file = "psycopg2_binary-2.9.9-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:f9b5571d33660d5009a8b3c25dc1db560206e2d2f89d3df1cb32d72c0d117d52"}, - {file = "psycopg2_binary-2.9.9-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:420f9bbf47a02616e8554e825208cb947969451978dceb77f95ad09c37791dae"}, - {file = "psycopg2_binary-2.9.9-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:4154ad09dac630a0f13f37b583eae260c6aa885d67dfbccb5b02c33f31a6d420"}, - {file = "psycopg2_binary-2.9.9-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a148c5d507bb9b4f2030a2025c545fccb0e1ef317393eaba42e7eabd28eb6041"}, - {file = "psycopg2_binary-2.9.9-cp37-cp37m-win32.whl", hash = "sha256:68fc1f1ba168724771e38bee37d940d2865cb0f562380a1fb1ffb428b75cb692"}, - {file = "psycopg2_binary-2.9.9-cp37-cp37m-win_amd64.whl", hash = "sha256:281309265596e388ef483250db3640e5f414168c5a67e9c665cafce9492eda2f"}, - {file = "psycopg2_binary-2.9.9-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:60989127da422b74a04345096c10d416c2b41bd7bf2a380eb541059e4e999980"}, - {file = "psycopg2_binary-2.9.9-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:246b123cc54bb5361588acc54218c8c9fb73068bf227a4a531d8ed56fa3ca7d6"}, - {file = "psycopg2_binary-2.9.9-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:34eccd14566f8fe14b2b95bb13b11572f7c7d5c36da61caf414d23b91fcc5d94"}, - {file = "psycopg2_binary-2.9.9-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:18d0ef97766055fec15b5de2c06dd8e7654705ce3e5e5eed3b6651a1d2a9a152"}, - {file = "psycopg2_binary-2.9.9-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d3f82c171b4ccd83bbaf35aa05e44e690113bd4f3b7b6cc54d2219b132f3ae55"}, - {file = "psycopg2_binary-2.9.9-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ead20f7913a9c1e894aebe47cccf9dc834e1618b7aa96155d2091a626e59c972"}, - {file = "psycopg2_binary-2.9.9-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ca49a8119c6cbd77375ae303b0cfd8c11f011abbbd64601167ecca18a87e7cdd"}, - {file = "psycopg2_binary-2.9.9-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:323ba25b92454adb36fa425dc5cf6f8f19f78948cbad2e7bc6cdf7b0d7982e59"}, - {file = "psycopg2_binary-2.9.9-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:1236ed0952fbd919c100bc839eaa4a39ebc397ed1c08a97fc45fee2a595aa1b3"}, - {file = "psycopg2_binary-2.9.9-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:729177eaf0aefca0994ce4cffe96ad3c75e377c7b6f4efa59ebf003b6d398716"}, - {file = "psycopg2_binary-2.9.9-cp38-cp38-win32.whl", hash = "sha256:804d99b24ad523a1fe18cc707bf741670332f7c7412e9d49cb5eab67e886b9b5"}, - {file = "psycopg2_binary-2.9.9-cp38-cp38-win_amd64.whl", hash = "sha256:a6cdcc3ede532f4a4b96000b6362099591ab4a3e913d70bcbac2b56c872446f7"}, - {file = "psycopg2_binary-2.9.9-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:72dffbd8b4194858d0941062a9766f8297e8868e1dd07a7b36212aaa90f49472"}, - {file = "psycopg2_binary-2.9.9-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:30dcc86377618a4c8f3b72418df92e77be4254d8f89f14b8e8f57d6d43603c0f"}, - {file = "psycopg2_binary-2.9.9-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:31a34c508c003a4347d389a9e6fcc2307cc2150eb516462a7a17512130de109e"}, - {file = "psycopg2_binary-2.9.9-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:15208be1c50b99203fe88d15695f22a5bed95ab3f84354c494bcb1d08557df67"}, - {file = "psycopg2_binary-2.9.9-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1873aade94b74715be2246321c8650cabf5a0d098a95bab81145ffffa4c13876"}, - {file = "psycopg2_binary-2.9.9-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a58c98a7e9c021f357348867f537017057c2ed7f77337fd914d0bedb35dace7"}, - {file = "psycopg2_binary-2.9.9-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4686818798f9194d03c9129a4d9a702d9e113a89cb03bffe08c6cf799e053291"}, - {file = "psycopg2_binary-2.9.9-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:ebdc36bea43063116f0486869652cb2ed7032dbc59fbcb4445c4862b5c1ecf7f"}, - {file = "psycopg2_binary-2.9.9-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:ca08decd2697fdea0aea364b370b1249d47336aec935f87b8bbfd7da5b2ee9c1"}, - {file = "psycopg2_binary-2.9.9-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ac05fb791acf5e1a3e39402641827780fe44d27e72567a000412c648a85ba860"}, - {file = "psycopg2_binary-2.9.9-cp39-cp39-win32.whl", hash = "sha256:9dba73be7305b399924709b91682299794887cbbd88e38226ed9f6712eabee90"}, - {file = "psycopg2_binary-2.9.9-cp39-cp39-win_amd64.whl", hash = "sha256:f7ae5d65ccfbebdfa761585228eb4d0df3a8b15cfb53bd953e713e09fbb12957"}, + {file = "protobuf-5.28.0-cp310-abi3-win32.whl", hash = "sha256:66c3edeedb774a3508ae70d87b3a19786445fe9a068dd3585e0cefa8a77b83d0"}, + {file = "protobuf-5.28.0-cp310-abi3-win_amd64.whl", hash = "sha256:6d7cc9e60f976cf3e873acb9a40fed04afb5d224608ed5c1a105db4a3f09c5b6"}, + {file = "protobuf-5.28.0-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:532627e8fdd825cf8767a2d2b94d77e874d5ddb0adefb04b237f7cc296748681"}, + {file = "protobuf-5.28.0-cp38-abi3-manylinux2014_aarch64.whl", hash = "sha256:018db9056b9d75eb93d12a9d35120f97a84d9a919bcab11ed56ad2d399d6e8dd"}, + {file = "protobuf-5.28.0-cp38-abi3-manylinux2014_x86_64.whl", hash = "sha256:6206afcb2d90181ae8722798dcb56dc76675ab67458ac24c0dd7d75d632ac9bd"}, + {file = "protobuf-5.28.0-cp38-cp38-win32.whl", hash = "sha256:eef7a8a2f4318e2cb2dee8666d26e58eaf437c14788f3a2911d0c3da40405ae8"}, + {file = "protobuf-5.28.0-cp38-cp38-win_amd64.whl", hash = "sha256:d001a73c8bc2bf5b5c1360d59dd7573744e163b3607fa92788b7f3d5fefbd9a5"}, + {file = "protobuf-5.28.0-cp39-cp39-win32.whl", hash = "sha256:dde9fcaa24e7a9654f4baf2a55250b13a5ea701493d904c54069776b99a8216b"}, + {file = "protobuf-5.28.0-cp39-cp39-win_amd64.whl", hash = "sha256:853db610214e77ee817ecf0514e0d1d052dff7f63a0c157aa6eabae98db8a8de"}, + {file = "protobuf-5.28.0-py3-none-any.whl", hash = "sha256:510ed78cd0980f6d3218099e874714cdf0d8a95582e7b059b06cabad855ed0a0"}, + {file = "protobuf-5.28.0.tar.gz", hash = "sha256:dde74af0fa774fa98892209992295adbfb91da3fa98c8f67a88afe8f5a349add"}, ] [[package]] name = "py-vapid" -version = "1.9.1" +version = "1.9.2" description = "Simple VAPID header generation library" optional = false python-versions = "*" files = [ - {file = "py_vapid-1.9.1.tar.gz", hash = "sha256:fe2b5461bf45c7baff1039df6981f03b87faa87cde0482addfa35b3fe636ac1b"}, + {file = "py_vapid-1.9.2-py3-none-any.whl", hash = "sha256:4ccf8a00fc54f1f99f66fb543c96f2c82622508ad814b6e9225f2c26948934d7"}, + {file = "py_vapid-1.9.2.tar.gz", hash = "sha256:3c8973b6cf8384ad0c9ae64d6270ccc480e0b92c702d8f5ea2cc03e6b51247f9"}, ] [package.dependencies] @@ -1589,54 +1727,54 @@ files = [ [[package]] name = "pydantic" -version = "1.10.17" +version = "1.10.18" description = "Data validation and settings management using python type hints" optional = false python-versions = ">=3.7" files = [ - {file = "pydantic-1.10.17-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0fa51175313cc30097660b10eec8ca55ed08bfa07acbfe02f7a42f6c242e9a4b"}, - {file = "pydantic-1.10.17-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c7e8988bb16988890c985bd2093df9dd731bfb9d5e0860db054c23034fab8f7a"}, - {file = "pydantic-1.10.17-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:371dcf1831f87c9e217e2b6a0c66842879a14873114ebb9d0861ab22e3b5bb1e"}, - {file = "pydantic-1.10.17-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4866a1579c0c3ca2c40575398a24d805d4db6cb353ee74df75ddeee3c657f9a7"}, - {file = "pydantic-1.10.17-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:543da3c6914795b37785703ffc74ba4d660418620cc273490d42c53949eeeca6"}, - {file = "pydantic-1.10.17-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7623b59876f49e61c2e283551cc3647616d2fbdc0b4d36d3d638aae8547ea681"}, - {file = "pydantic-1.10.17-cp310-cp310-win_amd64.whl", hash = "sha256:409b2b36d7d7d19cd8310b97a4ce6b1755ef8bd45b9a2ec5ec2b124db0a0d8f3"}, - {file = "pydantic-1.10.17-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:fa43f362b46741df8f201bf3e7dff3569fa92069bcc7b4a740dea3602e27ab7a"}, - {file = "pydantic-1.10.17-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2a72d2a5ff86a3075ed81ca031eac86923d44bc5d42e719d585a8eb547bf0c9b"}, - {file = "pydantic-1.10.17-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b4ad32aed3bf5eea5ca5decc3d1bbc3d0ec5d4fbcd72a03cdad849458decbc63"}, - {file = "pydantic-1.10.17-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aeb4e741782e236ee7dc1fb11ad94dc56aabaf02d21df0e79e0c21fe07c95741"}, - {file = "pydantic-1.10.17-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:d2f89a719411cb234105735a520b7c077158a81e0fe1cb05a79c01fc5eb59d3c"}, - {file = "pydantic-1.10.17-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:db3b48d9283d80a314f7a682f7acae8422386de659fffaba454b77a083c3937d"}, - {file = "pydantic-1.10.17-cp311-cp311-win_amd64.whl", hash = "sha256:9c803a5113cfab7bbb912f75faa4fc1e4acff43e452c82560349fff64f852e1b"}, - {file = "pydantic-1.10.17-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:820ae12a390c9cbb26bb44913c87fa2ff431a029a785642c1ff11fed0a095fcb"}, - {file = "pydantic-1.10.17-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c1e51d1af306641b7d1574d6d3307eaa10a4991542ca324f0feb134fee259815"}, - {file = "pydantic-1.10.17-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e53fb834aae96e7b0dadd6e92c66e7dd9cdf08965340ed04c16813102a47fab"}, - {file = "pydantic-1.10.17-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0e2495309b1266e81d259a570dd199916ff34f7f51f1b549a0d37a6d9b17b4dc"}, - {file = "pydantic-1.10.17-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:098ad8de840c92ea586bf8efd9e2e90c6339d33ab5c1cfbb85be66e4ecf8213f"}, - {file = "pydantic-1.10.17-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:525bbef620dac93c430d5d6bdbc91bdb5521698d434adf4434a7ef6ffd5c4b7f"}, - {file = "pydantic-1.10.17-cp312-cp312-win_amd64.whl", hash = "sha256:6654028d1144df451e1da69a670083c27117d493f16cf83da81e1e50edce72ad"}, - {file = "pydantic-1.10.17-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c87cedb4680d1614f1d59d13fea353faf3afd41ba5c906a266f3f2e8c245d655"}, - {file = "pydantic-1.10.17-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11289fa895bcbc8f18704efa1d8020bb9a86314da435348f59745473eb042e6b"}, - {file = "pydantic-1.10.17-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:94833612d6fd18b57c359a127cbfd932d9150c1b72fea7c86ab58c2a77edd7c7"}, - {file = "pydantic-1.10.17-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:d4ecb515fa7cb0e46e163ecd9d52f9147ba57bc3633dca0e586cdb7a232db9e3"}, - {file = "pydantic-1.10.17-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:7017971ffa7fd7808146880aa41b266e06c1e6e12261768a28b8b41ba55c8076"}, - {file = "pydantic-1.10.17-cp37-cp37m-win_amd64.whl", hash = "sha256:e840e6b2026920fc3f250ea8ebfdedf6ea7a25b77bf04c6576178e681942ae0f"}, - {file = "pydantic-1.10.17-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bfbb18b616abc4df70591b8c1ff1b3eabd234ddcddb86b7cac82657ab9017e33"}, - {file = "pydantic-1.10.17-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ebb249096d873593e014535ab07145498957091aa6ae92759a32d40cb9998e2e"}, - {file = "pydantic-1.10.17-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8c209af63ccd7b22fba94b9024e8b7fd07feffee0001efae50dd99316b27768"}, - {file = "pydantic-1.10.17-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d4b40c9e13a0b61583e5599e7950490c700297b4a375b55b2b592774332798b7"}, - {file = "pydantic-1.10.17-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:c31d281c7485223caf6474fc2b7cf21456289dbaa31401844069b77160cab9c7"}, - {file = "pydantic-1.10.17-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ae5184e99a060a5c80010a2d53c99aee76a3b0ad683d493e5f0620b5d86eeb75"}, - {file = "pydantic-1.10.17-cp38-cp38-win_amd64.whl", hash = "sha256:ad1e33dc6b9787a6f0f3fd132859aa75626528b49cc1f9e429cdacb2608ad5f0"}, - {file = "pydantic-1.10.17-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7e17c0ee7192e54a10943f245dc79e36d9fe282418ea05b886e1c666063a7b54"}, - {file = "pydantic-1.10.17-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:cafb9c938f61d1b182dfc7d44a7021326547b7b9cf695db5b68ec7b590214773"}, - {file = "pydantic-1.10.17-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95ef534e3c22e5abbdbdd6f66b6ea9dac3ca3e34c5c632894f8625d13d084cbe"}, - {file = "pydantic-1.10.17-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62d96b8799ae3d782df7ec9615cb59fc32c32e1ed6afa1b231b0595f6516e8ab"}, - {file = "pydantic-1.10.17-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:ab2f976336808fd5d539fdc26eb51f9aafc1f4b638e212ef6b6f05e753c8011d"}, - {file = "pydantic-1.10.17-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b8ad363330557beac73159acfbeed220d5f1bfcd6b930302a987a375e02f74fd"}, - {file = "pydantic-1.10.17-cp39-cp39-win_amd64.whl", hash = "sha256:48db882e48575ce4b39659558b2f9f37c25b8d348e37a2b4e32971dd5a7d6227"}, - {file = "pydantic-1.10.17-py3-none-any.whl", hash = "sha256:e41b5b973e5c64f674b3b4720286ded184dcc26a691dd55f34391c62c6934688"}, - {file = "pydantic-1.10.17.tar.gz", hash = "sha256:f434160fb14b353caf634149baaf847206406471ba70e64657c1e8330277a991"}, + {file = "pydantic-1.10.18-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e405ffcc1254d76bb0e760db101ee8916b620893e6edfbfee563b3c6f7a67c02"}, + {file = "pydantic-1.10.18-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e306e280ebebc65040034bff1a0a81fd86b2f4f05daac0131f29541cafd80b80"}, + {file = "pydantic-1.10.18-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11d9d9b87b50338b1b7de4ebf34fd29fdb0d219dc07ade29effc74d3d2609c62"}, + {file = "pydantic-1.10.18-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b661ce52c7b5e5f600c0c3c5839e71918346af2ef20062705ae76b5c16914cab"}, + {file = "pydantic-1.10.18-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:c20f682defc9ef81cd7eaa485879ab29a86a0ba58acf669a78ed868e72bb89e0"}, + {file = "pydantic-1.10.18-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c5ae6b7c8483b1e0bf59e5f1843e4fd8fd405e11df7de217ee65b98eb5462861"}, + {file = "pydantic-1.10.18-cp310-cp310-win_amd64.whl", hash = "sha256:74fe19dda960b193b0eb82c1f4d2c8e5e26918d9cda858cbf3f41dd28549cb70"}, + {file = "pydantic-1.10.18-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:72fa46abace0a7743cc697dbb830a41ee84c9db8456e8d77a46d79b537efd7ec"}, + {file = "pydantic-1.10.18-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ef0fe7ad7cbdb5f372463d42e6ed4ca9c443a52ce544472d8842a0576d830da5"}, + {file = "pydantic-1.10.18-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a00e63104346145389b8e8f500bc6a241e729feaf0559b88b8aa513dd2065481"}, + {file = "pydantic-1.10.18-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae6fa2008e1443c46b7b3a5eb03800121868d5ab6bc7cda20b5df3e133cde8b3"}, + {file = "pydantic-1.10.18-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:9f463abafdc92635da4b38807f5b9972276be7c8c5121989768549fceb8d2588"}, + {file = "pydantic-1.10.18-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3445426da503c7e40baccefb2b2989a0c5ce6b163679dd75f55493b460f05a8f"}, + {file = "pydantic-1.10.18-cp311-cp311-win_amd64.whl", hash = "sha256:467a14ee2183bc9c902579bb2f04c3d3dac00eff52e252850509a562255b2a33"}, + {file = "pydantic-1.10.18-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:efbc8a7f9cb5fe26122acba1852d8dcd1e125e723727c59dcd244da7bdaa54f2"}, + {file = "pydantic-1.10.18-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:24a4a159d0f7a8e26bf6463b0d3d60871d6a52eac5bb6a07a7df85c806f4c048"}, + {file = "pydantic-1.10.18-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b74be007703547dc52e3c37344d130a7bfacca7df112a9e5ceeb840a9ce195c7"}, + {file = "pydantic-1.10.18-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fcb20d4cb355195c75000a49bb4a31d75e4295200df620f454bbc6bdf60ca890"}, + {file = "pydantic-1.10.18-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:46f379b8cb8a3585e3f61bf9ae7d606c70d133943f339d38b76e041ec234953f"}, + {file = "pydantic-1.10.18-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:cbfbca662ed3729204090c4d09ee4beeecc1a7ecba5a159a94b5a4eb24e3759a"}, + {file = "pydantic-1.10.18-cp312-cp312-win_amd64.whl", hash = "sha256:c6d0a9f9eccaf7f438671a64acf654ef0d045466e63f9f68a579e2383b63f357"}, + {file = "pydantic-1.10.18-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3d5492dbf953d7d849751917e3b2433fb26010d977aa7a0765c37425a4026ff1"}, + {file = "pydantic-1.10.18-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe734914977eed33033b70bfc097e1baaffb589517863955430bf2e0846ac30f"}, + {file = "pydantic-1.10.18-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:15fdbe568beaca9aacfccd5ceadfb5f1a235087a127e8af5e48df9d8a45ae85c"}, + {file = "pydantic-1.10.18-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c3e742f62198c9eb9201781fbebe64533a3bbf6a76a91b8d438d62b813079dbc"}, + {file = "pydantic-1.10.18-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:19a3bd00b9dafc2cd7250d94d5b578edf7a0bd7daf102617153ff9a8fa37871c"}, + {file = "pydantic-1.10.18-cp37-cp37m-win_amd64.whl", hash = "sha256:2ce3fcf75b2bae99aa31bd4968de0474ebe8c8258a0110903478bd83dfee4e3b"}, + {file = "pydantic-1.10.18-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:335a32d72c51a313b33fa3a9b0fe283503272ef6467910338e123f90925f0f03"}, + {file = "pydantic-1.10.18-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:34a3613c7edb8c6fa578e58e9abe3c0f5e7430e0fc34a65a415a1683b9c32d9a"}, + {file = "pydantic-1.10.18-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e9ee4e6ca1d9616797fa2e9c0bfb8815912c7d67aca96f77428e316741082a1b"}, + {file = "pydantic-1.10.18-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:23e8ec1ce4e57b4f441fc91e3c12adba023fedd06868445a5b5f1d48f0ab3682"}, + {file = "pydantic-1.10.18-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:44ae8a3e35a54d2e8fa88ed65e1b08967a9ef8c320819a969bfa09ce5528fafe"}, + {file = "pydantic-1.10.18-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d5389eb3b48a72da28c6e061a247ab224381435256eb541e175798483368fdd3"}, + {file = "pydantic-1.10.18-cp38-cp38-win_amd64.whl", hash = "sha256:069b9c9fc645474d5ea3653788b544a9e0ccd3dca3ad8c900c4c6eac844b4620"}, + {file = "pydantic-1.10.18-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:80b982d42515632eb51f60fa1d217dfe0729f008e81a82d1544cc392e0a50ddf"}, + {file = "pydantic-1.10.18-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:aad8771ec8dbf9139b01b56f66386537c6fe4e76c8f7a47c10261b69ad25c2c9"}, + {file = "pydantic-1.10.18-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:941a2eb0a1509bd7f31e355912eb33b698eb0051730b2eaf9e70e2e1589cae1d"}, + {file = "pydantic-1.10.18-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:65f7361a09b07915a98efd17fdec23103307a54db2000bb92095457ca758d485"}, + {file = "pydantic-1.10.18-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:6951f3f47cb5ca4da536ab161ac0163cab31417d20c54c6de5ddcab8bc813c3f"}, + {file = "pydantic-1.10.18-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7a4c5eec138a9b52c67f664c7d51d4c7234c5ad65dd8aacd919fb47445a62c86"}, + {file = "pydantic-1.10.18-cp39-cp39-win_amd64.whl", hash = "sha256:49e26c51ca854286bffc22b69787a8d4063a62bf7d83dc21d44d2ff426108518"}, + {file = "pydantic-1.10.18-py3-none-any.whl", hash = "sha256:06a189b81ffc52746ec9c8c007f16e5167c8b0a696e1a726369327e3db7b2a82"}, + {file = "pydantic-1.10.18.tar.gz", hash = "sha256:baebdff1907d1d96a139c25136a9bb7d17e118f133a76a2ef3b845e831e3403a"}, ] [package.dependencies] @@ -1677,13 +1815,13 @@ files = [ [[package]] name = "pyln-client" -version = "24.5" +version = "24.8.1" description = "Client library and plugin library for Core Lightning" optional = false python-versions = "<4.0,>=3.8" files = [ - {file = "pyln_client-24.5-py3-none-any.whl", hash = "sha256:b1c7fc8644c0668472ba9cc5d45b6fe88f44bae396f624f0b1a09695011fce0d"}, - {file = "pyln_client-24.5.tar.gz", hash = "sha256:642af007f4b0ea75f7c1771b7a4563acf858e0e761023d84b7f61fef13cf3888"}, + {file = "pyln_client-24.8.1-py3-none-any.whl", hash = "sha256:4a389de96813a23b587007f181a5d4ba37bb8a4ac6bed7074a591b6b710e4615"}, + {file = "pyln_client-24.8.1.tar.gz", hash = "sha256:47e1bcadc91df511b7dbd66059d25a6c67fb0d49953291762272abf151fe8846"}, ] [package.dependencies] @@ -1692,20 +1830,20 @@ pyln-proto = ">=23" [[package]] name = "pyln-proto" -version = "24.5" +version = "24.8.2" description = "This package implements some of the Lightning Network protocol in pure python. It is intended for protocol testing and some minor tooling only. It is not deemed secure enough to handle any amount of real funds (you have been warned!)." optional = false python-versions = "<4.0,>=3.8" files = [ - {file = "pyln_proto-24.5-py3-none-any.whl", hash = "sha256:78b9982412cfea8172dfafe217001bdf3d6ee8d585f138b8868925e47a8c54b2"}, - {file = "pyln_proto-24.5.tar.gz", hash = "sha256:b6e7a0cd5bd3905d743ec2c3ef93233271062e0abf0b7647a449ff71c0f20074"}, + {file = "pyln_proto-24.8.2-py3-none-any.whl", hash = "sha256:9c6c080c41fff40b119ea518fae37b1c8d4e917fa55389002afceffd4850ec98"}, + {file = "pyln_proto-24.8.2.tar.gz", hash = "sha256:efa222284e2990f7227f0243acc0e9ec5acd3bb89bb66ecad9f7dfb22b09fc90"}, ] [package.dependencies] base58 = ">=2.1.1,<3.0.0" bitstring = ">=4.1.0,<5.0.0" -coincurve = ">=18,<19" -cryptography = ">=41,<42" +coincurve = ">=20,<21" +cryptography = ">=42,<43" PySocks = ">=1,<2" [[package]] @@ -1774,6 +1912,20 @@ pytest = ">=7.0.0" docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1.0)"] testing = ["coverage (>=6.2)", "flaky (>=3.5.0)", "hypothesis (>=5.7.1)", "mypy (>=0.931)", "pytest-trio (>=0.7.0)"] +[[package]] +name = "pytest-md" +version = "0.2.0" +description = "Plugin for generating Markdown reports for pytest results" +optional = false +python-versions = ">=3.6" +files = [ + {file = "pytest-md-0.2.0.tar.gz", hash = "sha256:3b248d5b360ea5198e05b4f49c7442234812809a63137ec6cdd3643a40cf0112"}, + {file = "pytest_md-0.2.0-py3-none-any.whl", hash = "sha256:4c4cd16fea6d1485e87ee254558712c804a96d2aa9674b780e7eb8fb6526e1d1"}, +] + +[package.dependencies] +pytest = ">=4.2.1" + [[package]] name = "python-crontab" version = "3.2.0" @@ -1840,79 +1992,66 @@ six = ">=1.15.0" [[package]] name = "pyyaml" -version = "6.0.1" +version = "6.0.2" description = "YAML parser and emitter for Python" optional = false -python-versions = ">=3.6" -files = [ - {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, - {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, - {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, - {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, - {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, - {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, - {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, - {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, - {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, - {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, - {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, - {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, - {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, - {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, - {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, - {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, - {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, - {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, - {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, - {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, - {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, - {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, - {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, - {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, - {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"}, - {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"}, - {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"}, - {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"}, - {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"}, - {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"}, - {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"}, - {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"}, - {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"}, - {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"}, - {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, - {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, - {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, - {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, - {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, - {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, - {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, - {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"}, - {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, - {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, - {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, - {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, - {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, - {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, - {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, -] - -[[package]] -name = "represent" -version = "2.1" -description = "Create __repr__ automatically or declaratively." -optional = false python-versions = ">=3.8" files = [ - {file = "Represent-2.1-py3-none-any.whl", hash = "sha256:94fd22d7fec378240c598b20b233f80545ec7eb1131076e2d3d759cee9be2588"}, - {file = "Represent-2.1.tar.gz", hash = "sha256:0b2d015c14e7ba6b3b5e6a7ba131a952013fe944339ac538764ce728a75dbcac"}, + {file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"}, + {file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed"}, + {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180"}, + {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68"}, + {file = "PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99"}, + {file = "PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e"}, + {file = "PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774"}, + {file = "PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85"}, + {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4"}, + {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e"}, + {file = "PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5"}, + {file = "PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44"}, + {file = "PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab"}, + {file = "PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476"}, + {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48"}, + {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b"}, + {file = "PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4"}, + {file = "PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8"}, + {file = "PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba"}, + {file = "PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5"}, + {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc"}, + {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652"}, + {file = "PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183"}, + {file = "PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563"}, + {file = "PyYAML-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083"}, + {file = "PyYAML-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706"}, + {file = "PyYAML-6.0.2-cp38-cp38-win32.whl", hash = "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a"}, + {file = "PyYAML-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff"}, + {file = "PyYAML-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d"}, + {file = "PyYAML-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19"}, + {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e"}, + {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725"}, + {file = "PyYAML-6.0.2-cp39-cp39-win32.whl", hash = "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631"}, + {file = "PyYAML-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8"}, + {file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"}, ] -[package.extras] -docstest = ["furo", "parver", "sphinx"] -test = ["ipython", "pytest", "rich"] - [[package]] name = "requests" version = "2.32.3" @@ -2047,79 +2186,80 @@ files = [ [[package]] name = "sqlalchemy" -version = "1.3.24" +version = "1.4.54" description = "Database Abstraction Library" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -files = [ - {file = "SQLAlchemy-1.3.24-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:87a2725ad7d41cd7376373c15fd8bf674e9c33ca56d0b8036add2d634dba372e"}, - {file = "SQLAlchemy-1.3.24-cp27-cp27m-win32.whl", hash = "sha256:f597a243b8550a3a0b15122b14e49d8a7e622ba1c9d29776af741f1845478d79"}, - {file = "SQLAlchemy-1.3.24-cp27-cp27m-win_amd64.whl", hash = "sha256:fc4cddb0b474b12ed7bdce6be1b9edc65352e8ce66bc10ff8cbbfb3d4047dbf4"}, - {file = "SQLAlchemy-1.3.24-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:f1149d6e5c49d069163e58a3196865e4321bad1803d7886e07d8710de392c548"}, - {file = "SQLAlchemy-1.3.24-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:14f0eb5db872c231b20c18b1e5806352723a3a89fb4254af3b3e14f22eaaec75"}, - {file = "SQLAlchemy-1.3.24-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:e98d09f487267f1e8d1179bf3b9d7709b30a916491997137dd24d6ae44d18d79"}, - {file = "SQLAlchemy-1.3.24-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:fc1f2a5a5963e2e73bac4926bdaf7790c4d7d77e8fc0590817880e22dd9d0b8b"}, - {file = "SQLAlchemy-1.3.24-cp35-cp35m-win32.whl", hash = "sha256:f3c5c52f7cb8b84bfaaf22d82cb9e6e9a8297f7c2ed14d806a0f5e4d22e83fb7"}, - {file = "SQLAlchemy-1.3.24-cp35-cp35m-win_amd64.whl", hash = "sha256:0352db1befcbed2f9282e72843f1963860bf0e0472a4fa5cf8ee084318e0e6ab"}, - {file = "SQLAlchemy-1.3.24-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:2ed6343b625b16bcb63c5b10523fd15ed8934e1ed0f772c534985e9f5e73d894"}, - {file = "SQLAlchemy-1.3.24-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:34fcec18f6e4b24b4a5f6185205a04f1eab1e56f8f1d028a2a03694ebcc2ddd4"}, - {file = "SQLAlchemy-1.3.24-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:e47e257ba5934550d7235665eee6c911dc7178419b614ba9e1fbb1ce6325b14f"}, - {file = "SQLAlchemy-1.3.24-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:816de75418ea0953b5eb7b8a74933ee5a46719491cd2b16f718afc4b291a9658"}, - {file = "SQLAlchemy-1.3.24-cp36-cp36m-win32.whl", hash = "sha256:26155ea7a243cbf23287f390dba13d7927ffa1586d3208e0e8d615d0c506f996"}, - {file = "SQLAlchemy-1.3.24-cp36-cp36m-win_amd64.whl", hash = "sha256:f03bd97650d2e42710fbe4cf8a59fae657f191df851fc9fc683ecef10746a375"}, - {file = "SQLAlchemy-1.3.24-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:a006d05d9aa052657ee3e4dc92544faae5fcbaafc6128217310945610d862d39"}, - {file = "SQLAlchemy-1.3.24-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:1e2f89d2e5e3c7a88e25a3b0e43626dba8db2aa700253023b82e630d12b37109"}, - {file = "SQLAlchemy-1.3.24-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:0d5d862b1cfbec5028ce1ecac06a3b42bc7703eb80e4b53fceb2738724311443"}, - {file = "SQLAlchemy-1.3.24-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:0172423a27fbcae3751ef016663b72e1a516777de324a76e30efa170dbd3dd2d"}, - {file = "SQLAlchemy-1.3.24-cp37-cp37m-win32.whl", hash = "sha256:d37843fb8df90376e9e91336724d78a32b988d3d20ab6656da4eb8ee3a45b63c"}, - {file = "SQLAlchemy-1.3.24-cp37-cp37m-win_amd64.whl", hash = "sha256:c10ff6112d119f82b1618b6dc28126798481b9355d8748b64b9b55051eb4f01b"}, - {file = "SQLAlchemy-1.3.24-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:861e459b0e97673af6cc5e7f597035c2e3acdfb2608132665406cded25ba64c7"}, - {file = "SQLAlchemy-1.3.24-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:5de2464c254380d8a6c20a2746614d5a436260be1507491442cf1088e59430d2"}, - {file = "SQLAlchemy-1.3.24-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:d375d8ccd3cebae8d90270f7aa8532fe05908f79e78ae489068f3b4eee5994e8"}, - {file = "SQLAlchemy-1.3.24-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:014ea143572fee1c18322b7908140ad23b3994036ef4c0d630110faf942652f8"}, - {file = "SQLAlchemy-1.3.24-cp38-cp38-win32.whl", hash = "sha256:6607ae6cd3a07f8a4c3198ffbf256c261661965742e2b5265a77cd5c679c9bba"}, - {file = "SQLAlchemy-1.3.24-cp38-cp38-win_amd64.whl", hash = "sha256:fcb251305fa24a490b6a9ee2180e5f8252915fb778d3dafc70f9cc3f863827b9"}, - {file = "SQLAlchemy-1.3.24-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:01aa5f803db724447c1d423ed583e42bf5264c597fd55e4add4301f163b0be48"}, - {file = "SQLAlchemy-1.3.24-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:4d0e3515ef98aa4f0dc289ff2eebb0ece6260bbf37c2ea2022aad63797eacf60"}, - {file = "SQLAlchemy-1.3.24-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:bce28277f308db43a6b4965734366f533b3ff009571ec7ffa583cb77539b84d6"}, - {file = "SQLAlchemy-1.3.24-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:8110e6c414d3efc574543109ee618fe2c1f96fa31833a1ff36cc34e968c4f233"}, - {file = "SQLAlchemy-1.3.24-cp39-cp39-win32.whl", hash = "sha256:ee5f5188edb20a29c1cc4a039b074fdc5575337c9a68f3063449ab47757bb064"}, - {file = "SQLAlchemy-1.3.24-cp39-cp39-win_amd64.whl", hash = "sha256:09083c2487ca3c0865dc588e07aeaa25416da3d95f7482c07e92f47e080aa17b"}, - {file = "SQLAlchemy-1.3.24.tar.gz", hash = "sha256:ebbb777cbf9312359b897bf81ba00dae0f5cb69fba2a18265dcc18a6f5ef7519"}, +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" +files = [ + {file = "SQLAlchemy-1.4.54-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:af00236fe21c4d4f4c227b6ccc19b44c594160cc3ff28d104cdce85855369277"}, + {file = "SQLAlchemy-1.4.54-cp310-cp310-manylinux1_x86_64.manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_5_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1183599e25fa38a1a322294b949da02b4f0da13dbc2688ef9dbe746df573f8a6"}, + {file = "SQLAlchemy-1.4.54-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1990d5a6a5dc358a0894c8ca02043fb9a5ad9538422001fb2826e91c50f1d539"}, + {file = "SQLAlchemy-1.4.54-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:14b3f4783275339170984cadda66e3ec011cce87b405968dc8d51cf0f9997b0d"}, + {file = "SQLAlchemy-1.4.54-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b24364150738ce488333b3fb48bfa14c189a66de41cd632796fbcacb26b4585"}, + {file = "SQLAlchemy-1.4.54-cp310-cp310-win32.whl", hash = "sha256:a8a72259a1652f192c68377be7011eac3c463e9892ef2948828c7d58e4829988"}, + {file = "SQLAlchemy-1.4.54-cp310-cp310-win_amd64.whl", hash = "sha256:b67589f7955924865344e6eacfdcf70675e64f36800a576aa5e961f0008cde2a"}, + {file = "SQLAlchemy-1.4.54-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:b05e0626ec1c391432eabb47a8abd3bf199fb74bfde7cc44a26d2b1b352c2c6e"}, + {file = "SQLAlchemy-1.4.54-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:13e91d6892b5fcb94a36ba061fb7a1f03d0185ed9d8a77c84ba389e5bb05e936"}, + {file = "SQLAlchemy-1.4.54-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb59a11689ff3c58e7652260127f9e34f7f45478a2f3ef831ab6db7bcd72108f"}, + {file = "SQLAlchemy-1.4.54-cp311-cp311-win32.whl", hash = "sha256:1390ca2d301a2708fd4425c6d75528d22f26b8f5cbc9faba1ddca136671432bc"}, + {file = "SQLAlchemy-1.4.54-cp311-cp311-win_amd64.whl", hash = "sha256:2b37931eac4b837c45e2522066bda221ac6d80e78922fb77c75eb12e4dbcdee5"}, + {file = "SQLAlchemy-1.4.54-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:3f01c2629a7d6b30d8afe0326b8c649b74825a0e1ebdcb01e8ffd1c920deb07d"}, + {file = "SQLAlchemy-1.4.54-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c24dd161c06992ed16c5e528a75878edbaeced5660c3db88c820f1f0d3fe1f4"}, + {file = "SQLAlchemy-1.4.54-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b5e0d47d619c739bdc636bbe007da4519fc953393304a5943e0b5aec96c9877c"}, + {file = "SQLAlchemy-1.4.54-cp312-cp312-win32.whl", hash = "sha256:12bc0141b245918b80d9d17eca94663dbd3f5266ac77a0be60750f36102bbb0f"}, + {file = "SQLAlchemy-1.4.54-cp312-cp312-win_amd64.whl", hash = "sha256:f941aaf15f47f316123e1933f9ea91a6efda73a161a6ab6046d1cde37be62c88"}, + {file = "SQLAlchemy-1.4.54-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:a41611835010ed4ea4c7aed1da5b58aac78ee7e70932a91ed2705a7b38e40f52"}, + {file = "SQLAlchemy-1.4.54-cp36-cp36m-manylinux1_x86_64.manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_5_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e8c1b9ecaf9f2590337d5622189aeb2f0dbc54ba0232fa0856cf390957584a9"}, + {file = "SQLAlchemy-1.4.54-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0de620f978ca273ce027769dc8db7e6ee72631796187adc8471b3c76091b809e"}, + {file = "SQLAlchemy-1.4.54-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c5a2530400a6e7e68fd1552a55515de6a4559122e495f73554a51cedafc11669"}, + {file = "SQLAlchemy-1.4.54-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d0cf7076c8578b3de4e43a046cc7a1af8466e1c3f5e64167189fe8958a4f9c02"}, + {file = "SQLAlchemy-1.4.54-cp37-cp37m-macosx_11_0_x86_64.whl", hash = "sha256:f1e1b92ee4ee9ffc68624ace218b89ca5ca667607ccee4541a90cc44999b9aea"}, + {file = "SQLAlchemy-1.4.54-cp37-cp37m-manylinux1_x86_64.manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_5_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41cffc63c7c83dfc30c4cab5b4308ba74440a9633c4509c51a0c52431fb0f8ab"}, + {file = "SQLAlchemy-1.4.54-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b5933c45d11cbd9694b1540aa9076816cc7406964c7b16a380fd84d3a5fe3241"}, + {file = "SQLAlchemy-1.4.54-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:cafe0ba3a96d0845121433cffa2b9232844a2609fce694fcc02f3f31214ece28"}, + {file = "SQLAlchemy-1.4.54-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a19f816f4702d7b1951d7576026c7124b9bfb64a9543e571774cf517b7a50b29"}, + {file = "SQLAlchemy-1.4.54-cp37-cp37m-win32.whl", hash = "sha256:76c2ba7b5a09863d0a8166fbc753af96d561818c572dbaf697c52095938e7be4"}, + {file = "SQLAlchemy-1.4.54-cp37-cp37m-win_amd64.whl", hash = "sha256:a86b0e4be775902a5496af4fb1b60d8a2a457d78f531458d294360b8637bb014"}, + {file = "SQLAlchemy-1.4.54-cp38-cp38-macosx_12_0_x86_64.whl", hash = "sha256:a49730afb716f3f675755afec109895cab95bc9875db7ffe2e42c1b1c6279482"}, + {file = "SQLAlchemy-1.4.54-cp38-cp38-manylinux1_x86_64.manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_5_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26e78444bc77d089e62874dc74df05a5c71f01ac598010a327881a48408d0064"}, + {file = "SQLAlchemy-1.4.54-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:02d2ecb9508f16ab9c5af466dfe5a88e26adf2e1a8d1c56eb616396ccae2c186"}, + {file = "SQLAlchemy-1.4.54-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:394b0135900b62dbf63e4809cdc8ac923182af2816d06ea61cd6763943c2cc05"}, + {file = "SQLAlchemy-1.4.54-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ed3576675c187e3baa80b02c4c9d0edfab78eff4e89dd9da736b921333a2432"}, + {file = "SQLAlchemy-1.4.54-cp38-cp38-win32.whl", hash = "sha256:fc9ffd9a38e21fad3e8c5a88926d57f94a32546e937e0be46142b2702003eba7"}, + {file = "SQLAlchemy-1.4.54-cp38-cp38-win_amd64.whl", hash = "sha256:a01bc25eb7a5688656c8770f931d5cb4a44c7de1b3cec69b84cc9745d1e4cc10"}, + {file = "SQLAlchemy-1.4.54-cp39-cp39-macosx_12_0_x86_64.whl", hash = "sha256:0b76bbb1cbae618d10679be8966f6d66c94f301cfc15cb49e2f2382563fb6efb"}, + {file = "SQLAlchemy-1.4.54-cp39-cp39-manylinux1_x86_64.manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_5_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdb2886c0be2c6c54d0651d5a61c29ef347e8eec81fd83afebbf7b59b80b7393"}, + {file = "SQLAlchemy-1.4.54-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:954816850777ac234a4e32b8c88ac1f7847088a6e90cfb8f0e127a1bf3feddff"}, + {file = "SQLAlchemy-1.4.54-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1d83cd1cc03c22d922ec94d0d5f7b7c96b1332f5e122e81b1a61fb22da77879a"}, + {file = "SQLAlchemy-1.4.54-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1576fba3616f79496e2f067262200dbf4aab1bb727cd7e4e006076686413c80c"}, + {file = "SQLAlchemy-1.4.54-cp39-cp39-win32.whl", hash = "sha256:3112de9e11ff1957148c6de1df2bc5cc1440ee36783412e5eedc6f53638a577d"}, + {file = "SQLAlchemy-1.4.54-cp39-cp39-win_amd64.whl", hash = "sha256:6da60fb24577f989535b8fc8b2ddc4212204aaf02e53c4c7ac94ac364150ed08"}, + {file = "sqlalchemy-1.4.54.tar.gz", hash = "sha256:4470fbed088c35dc20b78a39aaf4ae54fe81790c783b3264872a0224f437c31a"}, ] +[package.dependencies] +greenlet = {version = "!=0.4.17", markers = "python_version >= \"3\" and (platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\")"} + [package.extras] +aiomysql = ["aiomysql (>=0.2.0)", "greenlet (!=0.4.17)"] +aiosqlite = ["aiosqlite", "greenlet (!=0.4.17)", "typing_extensions (!=3.10.0.1)"] +asyncio = ["greenlet (!=0.4.17)"] +asyncmy = ["asyncmy (>=0.2.3,!=0.2.4)", "greenlet (!=0.4.17)"] +mariadb-connector = ["mariadb (>=1.0.1,!=1.1.2)", "mariadb (>=1.0.1,!=1.1.2)"] mssql = ["pyodbc"] -mssql-pymssql = ["pymssql"] -mssql-pyodbc = ["pyodbc"] -mysql = ["mysqlclient"] -oracle = ["cx-oracle"] -postgresql = ["psycopg2"] -postgresql-pg8000 = ["pg8000 (<1.16.6)"] +mssql-pymssql = ["pymssql", "pymssql"] +mssql-pyodbc = ["pyodbc", "pyodbc"] +mypy = ["mypy (>=0.910)", "sqlalchemy2-stubs"] +mysql = ["mysqlclient (>=1.4.0)", "mysqlclient (>=1.4.0,<2)"] +mysql-connector = ["mysql-connector-python", "mysql-connector-python"] +oracle = ["cx_oracle (>=7)", "cx_oracle (>=7,<8)"] +postgresql = ["psycopg2 (>=2.7)"] +postgresql-asyncpg = ["asyncpg", "asyncpg", "greenlet (!=0.4.17)", "greenlet (!=0.4.17)"] +postgresql-pg8000 = ["pg8000 (>=1.16.6,!=1.29.0)", "pg8000 (>=1.16.6,!=1.29.0)"] postgresql-psycopg2binary = ["psycopg2-binary"] postgresql-psycopg2cffi = ["psycopg2cffi"] pymysql = ["pymysql", "pymysql (<1)"] - -[[package]] -name = "sqlalchemy-aio" -version = "0.17.0" -description = "Async support for SQLAlchemy." -optional = false -python-versions = ">=3.6" -files = [ - {file = "sqlalchemy_aio-0.17.0-py3-none-any.whl", hash = "sha256:3f4aa392c38f032d6734826a4138a0f02ed3122d442ed142be1e5964f2a33b60"}, - {file = "sqlalchemy_aio-0.17.0.tar.gz", hash = "sha256:f531c7982662d71dfc0b117e77bb2ed544e25cd5361e76cf9f5208edcfb71f7b"}, -] - -[package.dependencies] -outcome = "*" -represent = ">=1.4" -sqlalchemy = "<1.4" - -[package.extras] -test = ["pytest (>=5.4)", "pytest-asyncio (>=0.14)", "pytest-trio (>=0.6)"] -test-noextras = ["pytest (>=5.4)", "pytest-asyncio (>=0.14)"] -trio = ["trio (>=0.15)"] +sqlcipher = ["sqlcipher3_binary"] [[package]] name = "sse-starlette" @@ -2140,13 +2280,13 @@ uvicorn = "*" [[package]] name = "starlette" -version = "0.37.2" +version = "0.40.0" description = "The little ASGI library that shines." optional = false python-versions = ">=3.8" files = [ - {file = "starlette-0.37.2-py3-none-any.whl", hash = "sha256:6fe59f29268538e5d0d182f2791a479a0c64638e6935d1c6989e63fb2699c6ee"}, - {file = "starlette-0.37.2.tar.gz", hash = "sha256:9af890290133b79fc3db55474ade20f6220a364a0402e0b556e7cd5e1e093823"}, + {file = "starlette-0.40.0-py3-none-any.whl", hash = "sha256:c494a22fae73805376ea6bf88439783ecfba9aac88a43911b48c653437e784c4"}, + {file = "starlette-0.40.0.tar.gz", hash = "sha256:1a3139688fb298ce5e2d661d37046a66ad996ce94be4d4983be019a23a04ea35"}, ] [package.dependencies] @@ -2158,38 +2298,13 @@ full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.7 [[package]] name = "tomli" -version = "2.0.1" +version = "2.1.0" description = "A lil' TOML parser" optional = false -python-versions = ">=3.7" -files = [ - {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, - {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, -] - -[[package]] -name = "types-cffi" -version = "1.16.0.20240331" -description = "Typing stubs for cffi" -optional = false -python-versions = ">=3.8" -files = [ - {file = "types-cffi-1.16.0.20240331.tar.gz", hash = "sha256:b8b20d23a2b89cfed5f8c5bc53b0cb8677c3aac6d970dbc771e28b9c698f5dee"}, - {file = "types_cffi-1.16.0.20240331-py3-none-any.whl", hash = "sha256:a363e5ea54a4eb6a4a105d800685fde596bc318089b025b27dee09849fe41ff0"}, -] - -[package.dependencies] -types-setuptools = "*" - -[[package]] -name = "types-setuptools" -version = "71.1.0.20240726" -description = "Typing stubs for setuptools" -optional = false python-versions = ">=3.8" files = [ - {file = "types-setuptools-71.1.0.20240726.tar.gz", hash = "sha256:85ba28e9461bb1be86ebba4db0f1c2408f2b11115b1966334ea9dc464e29303e"}, - {file = "types_setuptools-71.1.0.20240726-py3-none-any.whl", hash = "sha256:a7775376f36e0ff09bcad236bf265777590a66b11623e48c20bfc30f1444ea36"}, + {file = "tomli-2.1.0-py3-none-any.whl", hash = "sha256:a5c57c3d1c56f5ccdf89f6523458f60ef716e210fc47c4cfb188c5ba473e0391"}, + {file = "tomli-2.1.0.tar.gz", hash = "sha256:3f646cae2aec94e17d04973e4249548320197cfabdf130015d023de4b74d8ab8"}, ] [[package]] @@ -2205,13 +2320,13 @@ files = [ [[package]] name = "urllib3" -version = "2.2.2" +version = "2.2.3" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.8" files = [ - {file = "urllib3-2.2.2-py3-none-any.whl", hash = "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472"}, - {file = "urllib3-2.2.2.tar.gz", hash = "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168"}, + {file = "urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac"}, + {file = "urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9"}, ] [package.extras] @@ -2222,13 +2337,13 @@ zstd = ["zstandard (>=0.18.0)"] [[package]] name = "uvicorn" -version = "0.30.5" +version = "0.30.6" description = "The lightning-fast ASGI server." optional = false python-versions = ">=3.8" files = [ - {file = "uvicorn-0.30.5-py3-none-any.whl", hash = "sha256:b2d86de274726e9878188fa07576c9ceeff90a839e2b6e25c917fe05f5a6c835"}, - {file = "uvicorn-0.30.5.tar.gz", hash = "sha256:ac6fdbd4425c5fd17a9fe39daf4d4d075da6fdc80f653e5894cdc2fd98752bee"}, + {file = "uvicorn-0.30.6-py3-none-any.whl", hash = "sha256:65fd46fe3fda5bdc1b03b94eb634923ff18cd35b2f084813ea79d1f103f711b5"}, + {file = "uvicorn-0.30.6.tar.gz", hash = "sha256:4b15decdda1e72be08209e860a1e10e92439ad5b97cf44cc945fcbee66fc5788"}, ] [package.dependencies] @@ -2285,13 +2400,13 @@ test = ["Cython (>=0.29.36,<0.30.0)", "aiohttp (==3.9.0b0)", "aiohttp (>=3.8.1)" [[package]] name = "virtualenv" -version = "20.26.3" +version = "20.27.1" description = "Virtual Python Environment builder" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "virtualenv-20.26.3-py3-none-any.whl", hash = "sha256:8cc4a31139e796e9a7de2cd5cf2489de1217193116a8fd42328f1bd65f434589"}, - {file = "virtualenv-20.26.3.tar.gz", hash = "sha256:4c43a2a236279d9ea36a0d76f98d84bd6ca94ac4e0f4a3b9d46d05e10fea542a"}, + {file = "virtualenv-20.27.1-py3-none-any.whl", hash = "sha256:f11f1b8a29525562925f745563bfd48b189450f61fb34c4f9cc79dd5aa32a1f4"}, + {file = "virtualenv-20.27.1.tar.gz", hash = "sha256:142c6be10212543b32c6c45d3d3893dff89112cc588b7d0879ae5a1ec03a47ba"}, ] [package.dependencies] @@ -2493,20 +2608,24 @@ files = [ [[package]] name = "zipp" -version = "3.19.2" +version = "3.21.0" description = "Backport of pathlib-compatible object wrapper for zip files" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "zipp-3.19.2-py3-none-any.whl", hash = "sha256:f091755f667055f2d02b32c53771a7a6c8b47e1fdbc4b72a8b9072b3eef8015c"}, - {file = "zipp-3.19.2.tar.gz", hash = "sha256:bf1dcf6450f873a13e952a29504887c89e6de7506209e5b1bcc3460135d4de19"}, + {file = "zipp-3.21.0-py3-none-any.whl", hash = "sha256:ac1bbe05fd2991f160ebce24ffbac5f6d11d83dc90891255885223d42b3cd931"}, + {file = "zipp-3.21.0.tar.gz", hash = "sha256:2c9958f6430a2040341a52eb608ed6dd93ef4392e02ffe219417c1b28b5dd1f4"}, ] [package.extras] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] +cover = ["pytest-cov"] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy", "pytest-ruff (>=0.2.1)"] +enabler = ["pytest-enabler (>=2.2)"] +test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-ignore-flaky"] +type = ["pytest-mypy"] [metadata] lock-version = "2.0" python-versions = "^3.10 | ^3.9" -content-hash = "6b44707a3b75a9adc6fea66a2434468588b3cdc4993ae84e77bfbe01e68fb27a" +content-hash = "e353a743e101c1121a4275284a36b98e2033dbca94f03d7582e8d47c1af864aa" diff --git a/pyproject.toml b/pyproject.toml index b1e326a..d033272 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,8 +6,8 @@ authors = ["Riccardo Balbo "] [tool.poetry.dependencies] python = "^3.10 | ^3.9" -lnbits = "*" -psycopg2-binary = "^2.9.9" +lnbits = {version = "*", allow-prereleases = true} +mypy = "^1.13.0" [tool.poetry.group.dev.dependencies] black = "^24.3.0" @@ -16,27 +16,19 @@ pytest = "^7.3.2" mypy = "^1.5.1" pre-commit = "^3.2.2" ruff = "^0.3.2" -types-cffi = "^1.16.0.20240331" +pytest-md = "^0.2.0" [build-system] requires = ["poetry-core>=1.0.0"] build-backend = "poetry.core.masonry.api" [tool.mypy] -exclude = "(tests/*)" - [[tool.mypy.overrides]] module = [ "lnbits.*", - "lnurl.*", "loguru.*", "fastapi.*", "pydantic.*", - "pyqrcode.*", - "shortuuid.*", - "httpx.*", - "websocket.*", - "secp256k1.*", ] ignore_missing_imports = "True" @@ -52,9 +44,7 @@ line-length = 88 [tool.ruff] # Same as Black. + 10% rule of black line-length = 88 -# exclude = [ -# "nostr", -# ] + [tool.ruff.lint] # Enable: @@ -69,7 +59,8 @@ line-length = 88 # RUF - ruff # B - bugbear select = ["F", "E", "W", "I", "A", "C", "N", "UP", "RUF", "B"] -ignore = ["C901"] +# UP007: pyupgrade: use X | Y instead of Optional. (python3.10) +ignore = ["UP007"] # Allow autofix for all enabled rules (when `--fix`) is provided. fixable = ["ALL"] @@ -86,7 +77,7 @@ classmethod-decorators = [ # Ignore unused imports in __init__.py files. # [tool.ruff.lint.extend-per-file-ignores] -# "__init__.py" = ["F401", "F403"] +# "views_api.py" = ["F401"] # [tool.ruff.lint.mccabe] # max-complexity = 10 diff --git a/static/js/admin.js b/static/js/admin.js new file mode 100644 index 0000000..afacb7e --- /dev/null +++ b/static/js/admin.js @@ -0,0 +1,87 @@ +window.app = Vue.createApp({ + el: "#vue", + mixins: [windowMixin], + delimiters: ["${", "}"], + data: function () { + return { + entries: [], + columns: [ + { + name: "key", + required: true, + label: "Key", + align: "left", + field: (row) => row.key, + sortable: true, + }, + { + name: "value", + required: true, + label: "Value", + align: "left", + field: (row) => row.value, + sortable: true, + }, + ], + }; + }, + + methods: { + fetchConfig() { + this.entries = []; + LNbits.api + .request( + "GET", + "/nwcprovider/api/v1/config", + this.g.user.wallets[0].adminkey, + ) + .then((response) => { + const newEntries = []; + for (const [key, value] of Object.entries(response.data)) { + newEntries.push({ + key: key, + value: value, + }); + } + this.entries.length = 0; + this.entries.push(...newEntries); + }) + .catch(function (error) { + console.error("Error fetching config:", error); + }); + }, + async saveConfig() { + const data = {}; + for (const entry of this.entries) { + data[entry.key] = entry.value; + } + try { + const response = await LNbits.api.request( + "POST", + "/nwcprovider/api/v1/config", + this.g.user.wallets[0].adminkey, + data, + ); + Quasar.Notify.create({ + type: "positive", + message: "Config saved!", + }); + Quasar.Notify.create({ + type: "warning", + message: + "You need to restart the server for the changes to take effect!", + }); + } catch (error) { + Quasar.Notify.create({ + type: "negative", + message: "Error saving config: " + String(error), + }); + console.error("Error saving config:", error); + } + }, + }, + + created: function () { + this.fetchConfig(); + }, +}); diff --git a/static/js/index.js b/static/js/index.js new file mode 100644 index 0000000..e8a4ec1 --- /dev/null +++ b/static/js/index.js @@ -0,0 +1,386 @@ +window.app = Vue.createApp({ + el: "#vue", + mixins: [windowMixin], + delimiters: ["${", "}"], + data: function () { + return { + selectedWallet: null, + nodePermissions: [], + nwcEntries: [], + nwcsTable: { + columns: [ + { + name: "description", + align: "left", + label: "Description", + field: "description", + }, + { name: "status", align: "left", label: "Status", field: "status" }, + { + name: "last_used", + align: "left", + label: "Last used", + field: "last_used", + }, + { + name: "created_at", + align: "left", + label: "Created", + field: "created_at", + }, + { + name: "expires_at", + align: "left", + label: "Expires", + field: "expires_at", + }, + ], + pagination: { + rowsPerPage: 10, + }, + }, + connectDialog: { + show: false, + data: {}, + }, + pairingDialog: { + show: false, + data: { + pairingUrl: "", + }, + }, + pairingQrDialog: { + show: false, + data: { + pairingUrl: "", + }, + }, + connectionInfoDialog: { + show: false, + data: {}, + }, + }; + }, + + methods: { + showConnectDialog() { + const wallet = this.getWallet(); + if (!wallet) { + Quasar.Notify.create({ + type: "negative", + message: "Please select a wallet first", + }); + return; + } else { + this.connectDialog.show = true; + } + }, + openConnectionInfoDialog(data) { + this.connectionInfoDialog.data = data; + this.connectionInfoDialog.show = true; + }, + closeConnectionInfoDialog() { + this.connectionInfoDialog.show = false; + }, + openPairingUrl() { + const url = this.pairingDialog.data.pairingUrl; + if (url) window.open(url, "_blank"); + }, + go(url) { + window.open(url, "_blank"); + }, + async copyPairingUrl() { + const url = this.pairingDialog.data.pairingUrl; + if (url) { + try { + await navigator.clipboard.writeText(url); + Quasar.Notify.create({ + type: "positive", + message: "URL copied to clipboard", + }); + } catch (err) { + Quasar.Notify.create({ + type: "negative", + message: "Failed to copy URL.", + }); + } + } + }, + showPairingQR() { + this.pairingQrDialog.data.pairingUrl = this.pairingDialog.data.pairingUrl; + this.pairingQrDialog.show = true; + }, + closePairingQrDialog() { + this.pairingQrDialog.show = false; + }, + loadConnectDialogData() { + this.connectDialog.data = { + description: "", + expires_at: Date.now() + 1000 * 60 * 60 * 24 * 7, + neverExpires: true, + permissions: [], + budgets: [], + }; + for (const permission of this.nodePermissions) { + this.connectDialog.data.permissions.push({ + key: permission.key, + name: permission.name, + value: permission.value, + }); + } + }, + deleteBudget(index) { + this.connectDialog.data.budgets.splice(index, 1); + }, + addBudget() { + this.connectDialog.data.budgets.push({ + budget_sats: 1000, + used_budget_sats: 0, + created_at: new Date(new Date().setHours(0, 0, 0, 0)).getTime() / 1000, + expiration: "never", + }); + }, + closeConnectDialog() { + this.connectDialog.show = false; + this.loadConnectDialogData(); + }, + getWallet: function () { + let wallet = undefined; + for (let i = 0; i < this.g.user.wallets.length; i++) { + if (this.g.user.wallets[i].id == this.selectedWallet) { + wallet = this.g.user.wallets[i]; + break; + } + } + return wallet; + }, + async generateKeyPair() { + while (!window.NobleSecp256k1) { + await new Promise((resolve) => setTimeout(resolve, 1)); + } + const privKeyBytes = window.NobleSecp256k1.utils.randomPrivateKey(); + const pubKeyBytes = window.NobleSecp256k1.getPublicKey(privKeyBytes); + const out = { + privKeyBytes: privKeyBytes, + pubKeyBytes: pubKeyBytes, + privKey: window.NobleSecp256k1.etc.bytesToHex(privKeyBytes), + pubKey: window.NobleSecp256k1.etc.bytesToHex(pubKeyBytes.slice(1)), + }; + return out; + }, + deleteNWC: async function (pubkey) { + Quasar.Dialog.create({ + title: "Confirm Deletion", + message: "Are you sure you want to delete this connection?", + cancel: true, + persistent: true, + }) + .onOk(async () => { + try { + const wallet = this.getWallet(); + const response = await LNbits.api.request( + "DELETE", + `/nwcprovider/api/v1/nwc/${pubkey}`, + wallet.adminkey, + ); + this.loadNwcs(); + Quasar.Notify.create({ + type: "positive", + message: "Deleted successfully", + }); + } catch (error) { + LNbits.utils.notifyApiError(error); + } + }) + .onCancel(() => { + // User canceled the operation + }); + }, + loadNwcs: async function () { + const wallet = this.getWallet(); + if (!wallet) { + this.nwcs = []; + return; + } + try { + const response = await LNbits.api.request( + "GET", + "/nwcprovider/api/v1/nwc?include_expired=true&calculate_spent_budget=true", + wallet.adminkey, + ); + this.nwcs = response.data; + } catch (error) { + this.nwcs = []; + } + try { + const response = await LNbits.api.request( + "GET", + "/nwcprovider/api/v1/permissions", + wallet.adminkey, + ); + const permissions = []; + for (const [key, value] of Object.entries(response.data)) { + permissions.push({ + key: key, + name: value.name, + value: value.default, + }); + } + this.nodePermissions = permissions; + } catch (error) { + Lnbits.utils.notifyApiError(error); + } + this.loadConnectDialogData(); + const newTableEntries = []; + for (const nwc of this.nwcs) { + const t = Quasar.date.formatDate( + new Date(nwc.data.created_at * 1000), + "YYYY-MM-DD HH:mm", + ); + const e = + nwc.data.expires_at > 0 + ? Quasar.date.formatDate( + new Date(nwc.data.expires_at * 1000), + "YYYY-MM-DD HH:mm", + ) + : "Never"; + const l = Quasar.date.formatDate( + new Date(nwc.data.last_used * 1000), + "YYYY-MM-DD HH:mm", + ); + const nwcTableEntry = { + description: nwc.data.description, + created_at: t, + expires_at: e, + last_used: l, + pubkey: nwc.data.pubkey, + permissions: nwc.data.permissions, + budgets: [], + status: "Active", + }; + if ( + nwc.data.expires_at > 0 && + nwc.data.expires_at < new Date().getTime() / 1000 + ) { + nwcTableEntry.status = "Expired"; + } + for (const budget of nwc.budgets) { + const createdAt = Quasar.date.formatDate( + new Date(budget.created_at * 1000), + "YYYY-MM-DD HH:mm", + ); + let refreshWindow = budget.refresh_window; + if (refreshWindow <= 0) { + refreshWindow = "Never"; + } else if (refreshWindow == 60 * 60 * 24) { + refreshWindow = "Daily"; + } else if (refreshWindow == 60 * 60 * 24 * 7) { + refreshWindow = "Weekly"; + } else if (refreshWindow == 60 * 60 * 24 * 30) { + refreshWindow = "Monthly"; + } else if (refreshWindow == 60 * 60 * 24 * 365) { + refreshWindow = "Yearly"; + } + nwcTableEntry.budgets.push({ + budget_sats: budget.budget_msats / 1000, + used_budget_sats: budget.used_budget_msats / 1000, + created_at: createdAt, + refresh_window: refreshWindow, + }); + } + newTableEntries.push(nwcTableEntry); + } + this.nwcEntries = newTableEntries; + }, + closePairingDialog() { + this.pairingDialog.show = false; + }, + async showPairingDialog(secret) { + let response = await LNbits.api.request( + "GET", + "/nwcprovider/api/v1/pairing/{SECRET}", + ); + response = response.data; + response = response.replace("{SECRET}", secret); + this.pairingDialog.data.pairingUrl = response; + this.pairingDialog.show = true; + }, + async confirmConnectDialog() { + const keyPair = await this.generateKeyPair(); + // timestamp + let expires_at = 0; + if (!this.connectDialog.data.neverExpires) { + expires_at = + new Date(this.connectDialog.data.expires_at).getTime() / 1000; + } + const data = { + permissions: [], + description: this.connectDialog.data.description, + expires_at: expires_at, + budgets: [], + }; + for (const permission of this.connectDialog.data.permissions) { + if (permission.value) data.permissions.push(permission.key); + } + for (const budget of this.connectDialog.data.budgets) { + const budget_msats = budget.budget_sats * 1000; + let refresh_window = 0; + switch (budget.expiry) { + case "Daily": + refresh_window = 60 * 60 * 24; + break; + case "Weekly": + refresh_window = 60 * 60 * 24 * 7; + break; + case "Monthly": + refresh_window = 60 * 60 * 24 * 30; + break; + case "Yearly": + refresh_window = 60 * 60 * 24 * 365; + break; + case "Never": + refresh_window = 0; + break; + } + data.budgets.push({ + budget_msats: budget_msats, + refresh_window: refresh_window, + created_at: + new Date(new Date().setHours(0, 0, 0, 0)).getTime() / 1000, + }); + } + const wallet = this.getWallet(); + + try { + const response = await LNbits.api.request( + "PUT", + "/nwcprovider/api/v1/nwc/" + keyPair.pubKey, + wallet.adminkey, + data, + ); + this.closeConnectDialog(); + if ( + !response.data || + !response.data.data || + !response.data.data.pubkey + ) { + LNbits.utils.notifyApiError("Error creating nwc pairing"); + return; + } + this.showPairingDialog(keyPair.privKey); + } catch (error) { + LNbits.utils.notifyApiError(error); + } + this.loadNwcs(); + }, + }, + + created: function () { + this.loadNwcs(); + }, + watch: { + selectedWallet(newValue, oldValue) { + this.loadNwcs(); + }, + }, +}); diff --git a/tasks.py b/tasks.py index 356bb43..d06a80f 100644 --- a/tasks.py +++ b/tasks.py @@ -19,12 +19,23 @@ from .crud import get_config_nwc, get_nwc, tracked_spend_nwc from .execution_queue import execution_queue -from .models import NWCKey +from .models import GetNWC, NWCKey, TrackedSpendNWC from .nwcp import NWCServiceProvider +from .paranoia import ( + assert_boolean, + assert_sane_string, + assert_valid_bolt11, + assert_valid_expiration_seconds, + assert_valid_msats, + assert_valid_positive_int, + assert_valid_pubkey, + assert_valid_sha256, + assert_valid_wallet_id, +) from .permission import nwc_permissions -async def _check(nwc: Optional[NWCKey], method: str, payload: Dict) -> Optional[Dict]: +async def _check(nwc: Optional[NWCKey], method: str) -> Optional[Dict]: # check if not nwc: return { @@ -55,18 +66,29 @@ async def _process_invoice( amount_msats: int, description: Optional[str] = None, ): - async def execute_payment(): - return await pay_invoice( + + # hardening # + assert_valid_wallet_id(wallet_id) + assert_valid_pubkey(pubkey) + assert_valid_bolt11(invoice) + assert_valid_msats(amount_msats) + if description: + assert_sane_string(description) + # ## # + + async def execute_payment() -> str: + payment = await pay_invoice( wallet_id=wallet_id, payment_request=invoice, max_sat=int(ceil(amount_msats / 1000)), description=description or "", ) + return payment.payment_hash payment_hash = None try: in_budget, payment_hash = await tracked_spend_nwc( - pubkey, amount_msats, execute_payment + TrackedSpendNWC(pubkey=pubkey, amount_msats=amount_msats), execute_payment ) if not in_budget: error = { @@ -108,8 +130,13 @@ async def execute_payment(): async def _on_pay_invoice( sp: NWCServiceProvider, pubkey: str, payload: Dict ) -> List[Tuple[Optional[Dict], Optional[Dict], List]]: - nwc = await get_nwc(pubkey, None, False, True) - error = await _check(nwc, "pay_invoice", payload) + + # hardening # + assert_valid_pubkey(pubkey) + # ## # + + nwc = await get_nwc(GetNWC(pubkey=pubkey, refresh_last_used=True)) + error = await _check(nwc, "pay_invoice") if error: return [(None, error, [])] if not nwc: @@ -121,6 +148,12 @@ async def _on_pay_invoice( raise Exception("Missing invoice") invoice_data = bolt11_decode(invoice) amount_msats = int(invoice_data.amount_msat or 0) + + # hardening # + assert_valid_bolt11(invoice) + assert_valid_msats(amount_msats) + # ## # + res = await _process_invoice( nwc.wallet, pubkey, invoice, amount_msats, invoice_data.description ) @@ -138,8 +171,13 @@ async def _on_pay_invoice( async def _on_multi_pay_invoice( sp: NWCServiceProvider, pubkey: str, payload: Dict ) -> List[Tuple[Optional[Dict], Optional[Dict], List]]: - nwc = await get_nwc(pubkey, None, False, True) - error = await _check(nwc, "multi_pay_invoice", payload) + + # hardening # + assert_valid_pubkey(pubkey) + # ## # + + nwc = await get_nwc(GetNWC(pubkey=pubkey, refresh_last_used=True)) + error = await _check(nwc, "multi_pay_invoice") if error: return [(None, error, [])] if not nwc: @@ -160,6 +198,14 @@ async def _on_multi_pay_invoice( invoice = i.get("invoice", None) invoice_data = bolt11_decode(invoice) amount_msats = int(invoice_data.amount_msat or 0) + + # hardening # + assert_valid_bolt11(invoice) + assert_valid_msats(amount_msats) + if invoice_id: + assert_sane_string(invoice_id) + # ## # + res = await _process_invoice( nwc.wallet, pubkey, invoice, amount_msats, invoice_data.description ) @@ -184,8 +230,13 @@ async def _on_multi_pay_invoice( async def _on_make_invoice( sp: NWCServiceProvider, pubkey: str, payload: Dict ) -> List[Tuple[Optional[Dict], Optional[Dict], List]]: - nwc = await get_nwc(pubkey, None, False, True) - error = await _check(nwc, "make_invoice", payload) + + # hardening # + assert_valid_pubkey(pubkey) + # ## # + + nwc = await get_nwc(GetNWC(pubkey=pubkey, refresh_last_used=True)) + error = await _check(nwc, "make_invoice") if error: return [(None, error, [])] if not nwc: @@ -198,7 +249,18 @@ async def _on_make_invoice( description = params.get("description", "") description_hash = params.get("description_hash", None) expiry = params.get("expiry", None) - payment_hash, payment_request = await create_invoice( + + # hardening # + assert_valid_msats(amount_msats) + if description: + assert_sane_string(description) + if description_hash: + assert_valid_sha256(description_hash) + if expiry: + assert_valid_expiration_seconds(expiry) + # ## # + + payment = await create_invoice( wallet_id=nwc.wallet, amount=int(amount_msats / 1000), currency="sat", @@ -207,6 +269,8 @@ async def _on_make_invoice( unhashed_description=description.encode("utf-8"), expiry=expiry, ) + payment_hash = payment.payment_hash + payment_request = payment.bolt11 payment_status = await check_transaction_status( wallet_id=nwc.wallet, payment_hash=payment_hash ) @@ -236,8 +300,13 @@ async def _on_make_invoice( async def _on_lookup_invoice( sp: NWCServiceProvider, pubkey: str, payload: Dict ) -> List[Tuple[Optional[Dict], Optional[Dict], List]]: - nwc = await get_nwc(pubkey, None, False, True) - error = await _check(nwc, "lookup_invoice", payload) + + # hardening # + assert_valid_pubkey(pubkey) + # ## # + + nwc = await get_nwc(GetNWC(pubkey=pubkey, refresh_last_used=True)) + error = await _check(nwc, "lookup_invoice") if error: return [(None, error, [])] if not nwc: @@ -252,25 +321,36 @@ async def _on_lookup_invoice( if not payment_hash: invoice_data = bolt11_decode(invoice) payment_hash = invoice_data.payment_hash + + # hardening # + assert_valid_sha256(payment_hash) + assert_valid_bolt11(invoice) + # ## # + # Get payment data payment = await get_wallet_payment(nwc.wallet, payment_hash) if not payment: raise Exception("Payment not found") invoice_data = bolt11_decode(payment.bolt11) is_settled = not payment.pending - timestamp = payment.time or invoice_data.date + timestamp = int(payment.time.timestamp()) or int(invoice_data.date) + expiry = int(payment.expiry.timestamp()) or timestamp + 3600 + preimage = ( + payment.preimage + or "0000000000000000000000000000000000000000000000000000000000000000" + ) res: Dict = { "type": "outgoing" if payment.is_out else "incoming", "invoice": payment.bolt11, "description": ( invoice_data.description if invoice_data.description else payment.memo ), - "preimage": payment.preimage if is_settled or payment.is_in else None, + "preimage": preimage if is_settled or payment.is_in else None, "payment_hash": payment.payment_hash, "amount": abs(payment.msat), "fees_paid": abs(payment.fee), "created_at": timestamp, - "expires_at": payment.expiry if payment.expiry else timestamp + 3600, + "expires_at": expiry, "settled_at": timestamp if is_settled else None, "metadata": {}, } @@ -283,8 +363,12 @@ async def _on_lookup_invoice( async def _on_list_transactions( sp: NWCServiceProvider, pubkey: str, payload: Dict ) -> List[Tuple[Optional[Dict], Optional[Dict], List]]: - nwc = await get_nwc(pubkey, None, False, True) - error = await _check(nwc, "list_transactions", payload) + # hardening # + assert_valid_pubkey(pubkey) + # ## # + + nwc = await get_nwc(GetNWC(pubkey=pubkey, refresh_last_used=True)) + error = await _check(nwc, "list_transactions") if error: return [(None, error, [])] if not nwc: @@ -294,7 +378,17 @@ async def _on_list_transactions( limit = payload.get("limit", 10) offset = payload.get("offset", 0) unpaid = payload.get("unpaid", False) - tx_type = payload.get("type", None) + tx_type = payload.get("type", "") + + # hardening # + assert_valid_positive_int(tfrom) + assert_valid_positive_int(tto) + assert_valid_positive_int(limit) + assert_valid_positive_int(offset) + assert_boolean(unpaid) + assert_sane_string(tx_type) + # ## # + values = [] filters: Filters = Filters() filters.where(["time <= ?"]) @@ -317,6 +411,7 @@ async def _on_list_transactions( for p in history: invoice_data = bolt11_decode(p.bolt11) is_settled = not p.pending + timestamp = int(p.time.timestamp()) or invoice_data.date transactions.append( { "type": "outgoing" if p.is_out else "incoming", @@ -327,8 +422,8 @@ async def _on_list_transactions( "payment_hash": p.payment_hash, "amount": abs(p.msat), "fees_paid": p.fee, - "created_at": p.time, - "settled_at": p.time if is_settled else None, + "created_at": timestamp, + "settled_at": timestamp if is_settled else None, "metadata": {}, } ) @@ -339,8 +434,13 @@ async def _on_list_transactions( async def _on_get_balance( sp: NWCServiceProvider, pubkey: str, payload: Dict ) -> List[Tuple[Optional[Dict], Optional[Dict], List]]: - nwc = await get_nwc(pubkey, None, False, True) - error = await _check(nwc, "get_balance", payload) + + # hardening # + assert_valid_pubkey(pubkey) + # ## # + + nwc = await get_nwc(GetNWC(pubkey=pubkey, refresh_last_used=True)) + error = await _check(nwc, "get_balance") if error: return [(None, error, [])] if not nwc: @@ -357,8 +457,13 @@ async def _on_get_balance( async def _on_get_info( sp: NWCServiceProvider, pubkey: str, payload: Dict ) -> List[Tuple[Optional[Dict], Optional[Dict], List]]: - nwc = await get_nwc(pubkey, None, False, True) - error = await _check(nwc, "get_info", payload) + + # hardening # + assert_valid_pubkey(pubkey) + # ## # + + nwc = await get_nwc(GetNWC(pubkey=pubkey, refresh_last_used=True)) + error = await _check(nwc, "get_info") if error: return [(None, error, [])] if not nwc: @@ -394,7 +499,8 @@ async def _on_get_info( async def handle_nwc(): priv_key = await get_config_nwc("provider_key") relay = await get_config_nwc("relay") - nwcsp = NWCServiceProvider(priv_key, relay) + handle_missed_events = int(await get_config_nwc("handle_missed_events") or 0) + nwcsp = NWCServiceProvider(priv_key, relay, handle_missed_events) nwcsp.add_request_listener("pay_invoice", _on_pay_invoice) nwcsp.add_request_listener("multi_pay_invoice", _on_multi_pay_invoice) nwcsp.add_request_listener("make_invoice", _on_make_invoice) diff --git a/templates/nwcprovider/admin.html b/templates/nwcprovider/admin.html index dbd87ba..171a6d0 100644 --- a/templates/nwcprovider/admin.html +++ b/templates/nwcprovider/admin.html @@ -1,5 +1,7 @@ {% extends "base.html" %} {% from "macros.jinja" import window_vars with context -%} {% block page %} +%} {% block scripts %} {{ window_vars(user) }} + +{% endblock %} {% block page %}
@@ -11,20 +13,18 @@
- + + + + + ${entry.key} + + + + + + + -{% endblock %} {% block scripts %} {{ window_vars(user) }} - {% endblock %} diff --git a/templates/nwcprovider/index.html b/templates/nwcprovider/index.html index 89d5e63..143c7af 100644 --- a/templates/nwcprovider/index.html +++ b/templates/nwcprovider/index.html @@ -1,9 +1,11 @@ - - - - {% extends "base.html" %} {% from "macros.jinja" import window_vars with context -%} {% block page %} +%} {% block scripts %} {{ window_vars(user) }} + + +{% endblock %} {% block page %}
@@ -46,10 +48,10 @@
Connected Apps
@@ -99,8 +101,8 @@
Connected Apps
NWC Service provider

- Nostr Wallet Connect (NWC) are a way for applications to connect to a - remote lightning wallet. + Nostr Wallet Connect (NWC) is an open protocol to connect lightning + wallets to apps

@@ -402,397 +404,4 @@

Add connection

-{% endblock %} {% block scripts %} {{ window_vars(user) }} - - {% endblock %} diff --git a/tests/integration/.env b/tests/integration/.env index 0f1cedc..05905b6 100644 --- a/tests/integration/.env +++ b/tests/integration/.env @@ -206,7 +206,7 @@ LNBITS_EXTENSIONS_DEFAULT_INSTALL="tpos" # to use CockroachDB, specify LNBITS_DATABASE_URL=cockroachdb://... # for both PostgreSQL and CockroachDB, you'll need to install # psycopg2 as an additional dependency -LNBITS_DATA_FOLDER="./data" +LNBITS_DATA_FOLDER="/data" # LNBITS_DATABASE_URL="postgres://user:password@host:port/databasename" # the service fee (in percent) diff --git a/tests/integration/data.zip b/tests/integration/data.zip index e89b53ec073079d9ab15fdf7a1bef52f9bd25948..6f7c483711b58b4d3dee73510dee188a5de4901e 100644 GIT binary patch delta 74808 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 Utlw2Qw=WWOG&EPHJGXoP2WzddAOHXW literal 69158 zcmZ^~1z4QD(mxE8A}#L4Dekto6^ayhcXxMhao6JRy108=+>5)z;=VY`N1r3lIq!G= zxvov_%zfvVNivyCGFb)bH?UYxf5LL)y~bY;|BNu8NTF=(j4WN8^(|dYon7=z3|$PF zRaKCo;H&NP&HnXs^>_~j4ZHsa3hJ*&;V(P{Cf`@pdmTg?6!KiN|GW~r~dB>n&SImwc? zp^()2dg8WxI^g2{!HwmYMeZDX`zqs-TNlZj_Q+M;)sqiGZOf;gCn#bjq9&$lrlw}Q z1$E`(&gVC5Ul5oOYNw<~8@{T2{e(c~_(_M`d2{e{&)W-b2OS`+h^UF`+=%J?xYvTA z*GsjoZW_A3_!GLn=qr#(-)4a>R~{u_7(NZ{kaJF2Mo!LStCFRion4l%o>5MYL5}Cm zJ)wRvDG@pFU*xs&nv_3YLH-G=zqO~ zf;vCgn)>cl%L}0Say7}{SpV;m zP(BYWGdVCC8Xt0?TWUJaf0_zH_vE}xRO@7n;QmMbJ*aO6HlLC@TetgWs~Pn>!orNu z6Azor5F^MW;V^8psS{)uQp$4GDUVbYy;N0DNM>%%-v0Pz5j?hP(B9ELTa-p;`}ji_ zym~@ZA9(s9w0}Dpw_|!~k&2DcIt-xm^31XHsY>1Q_h6&0)SMpu;$Y;#$yEA@xTDgA zVj!D@5SV{&FAr0$H~KTGE0xY?Txv_e;Uvj5dkV)y^9qIDV-G~_!1Km4N$4d<|2~xG z2LA6R_LRh_S!r1uSyJo@h?&i!K&{q@1u7wNkzf4rC1Iq}cXQ;+Nq>AqX>9|t}? zfxFuv!PecQDF5#3Z0Hz$osPQOskODWm7+*oN&+%vEM&16S22}1O1d^0L(w=}!_^x0 z9Z!Iw88Fw(TvS>0^QZJ;1!yv>()7ILVo9_)bXFG|ye47SA2nDbYRKB?qLqViN^y2! z#m~TbObCzP#g+n>W_-L9mWdS}eQF;$d7mgot!xx*u$92-j%J%-p#o7xf(52@o<^OE ztO;U+N=BF{PFOUukw(541v2eBs*p-;{CHSwNjhgznd-0puN>nY_Sc2K&C{;4ij0V6 z#lS``n`uzdt*N!Rc1bilC`OYV2q?rWW~?uDeWO_UVNeZe)M?Zxja+HeCC)Ye@qKct zd4b7bNLlS&njX^&VYi22DS>oNF=<8-Vp@bPKHTpxrnK_BwDd0≫t}MFe~**zpJ& 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%0A&_o~6yfSs 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

wYI~3YZk|X_{*`qN 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 PW;Xm3!R_MCBEZ}KRm%5k diff --git a/tests/integration/start.sh b/tests/integration/start.sh index dd68b60..140f26a 100644 --- a/tests/integration/start.sh +++ b/tests/integration/start.sh @@ -1,5 +1,5 @@ #!/bin/bash - +set -e # cd in the script folder cd "$(dirname "$0")" @@ -27,18 +27,42 @@ ghcr.io/hoytech/strfry:latest # Start lnbits with the nwcprovider extension rm -Rf lnbits_itest_data unzip data.zip + +id=$(id -u) +gid=$(id -g) + + docker run --name=lnbits_nwcprovider_ext_lnbits_test \ -d \ --rm \ +--user $id:$gid \ -p 5002:5000 \ -v ${PWD}/.env:/app/.env \ --v ${PWD}/lnbits_itest_data/:/app/data \ --v ${PWD}/../../:/app/lnbits/extensions/nwcprovider:ro \ -lnbits/lnbits - +-v ${PWD}/lnbits_itest_data/:/data \ +-v ${PWD}/../../:/nwcprovider \ +-v ${PWD}/../../.devcontainer/start.sh:/start-lnbits.sh:ro \ +-v ${PWD}/../../.devcontainer/setup.sh:/setup.sh:ro \ +-v ${PWD}/../../.devcontainer/pre-setup.sh:/pre-setup.sh:ro \ +mcr.microsoft.com/devcontainers/python:1-3.12 bash -c "while true; do sleep 1000; done" docker network create lnbits_nwcprovider_ext_test_network || true docker network connect lnbits_nwcprovider_ext_test_network lnbits_nwcprovider_ext_nostr_test --alias nostr|| true docker network connect lnbits_nwcprovider_ext_test_network lnbits_nwcprovider_ext_lnbits_test --alias lnbits|| true +docker exec -u root lnbits_nwcprovider_ext_lnbits_test bash -c "id -u $id &>/dev/null || useradd -m -u $id tester" +docker exec -u root lnbits_nwcprovider_ext_lnbits_test bash -c "bash /pre-setup.sh" +docker exec --user $id:$gid lnbits_nwcprovider_ext_lnbits_test bash -c "curl -sSL https://install.python-poetry.org | python3 -" + +set +e +docker exec --user $id:$gid lnbits_nwcprovider_ext_lnbits_test bash -c "export PATH=\"\$HOME/.local/bin:\$PATH\" && bash /setup.sh /nwcprovider" +docker exec --user $id:$gid lnbits_nwcprovider_ext_lnbits_test bash -c "ln -s /app/.env \$HOME/lnbits/.env" + + +ARGS="" +if [ "$HEADLESS" != "" ]; +then + ARGS="-d" +fi +docker exec --user $id:$gid $ARGS lnbits_nwcprovider_ext_lnbits_test bash -c "export PATH=\"\$HOME/.local/bin:\$PATH\" && cd \$HOME/lnbits && poetry run lnbits" + diff --git a/tests/integration/test_all.py b/tests/integration/test_all.py index 0d4d38c..e965b0d 100644 --- a/tests/integration/test_all.py +++ b/tests/integration/test_all.py @@ -335,7 +335,7 @@ async def send_event(self, method, params): await self.ws.send(self._json_dumps(["EVENT", event])) async def wait_for( - self, result_type, callback=None, on_error_callback=None, timeout=10 + self, result_type, callback=None, on_error_callback=None, timeout=60 ): now = time.time() while True: @@ -850,3 +850,144 @@ async def test_budget_refresh(): await wallet3.close() await wallet1.close() + + +# Mostly AI generated pentests + + +@pytest.mark.asyncio +async def test_unauthorized_access(): + """Test accessing protected endpoints without valid API keys""" + async with httpx.AsyncClient() as client: + # privkey b758d3c535f8d089ce20473bafb33ee2f2f8deb94c97a0c5272cbf5bdc29f573 + # Try to create NWC without API key + resp = await client.put( + "http://localhost:5002/nwcprovider/api/v1/nwc/033c415d948f92aa7aa788ecfe49e49c3acae882d3dd2294574141bd786e18b6" + ) + assert resp.status_code == 401 + + # Try to access config endpoint without admin privileges + resp = await client.get("http://localhost:5002/nwcprovider/api/v1/config") + assert resp.status_code == 401 + + +@pytest.mark.asyncio +async def test_idor_vulnerability(): + """Test Insecure Direct Object Reference through pubkey manipulation""" + # Create NWC for wallet1 + nwc_wallet1 = await create_nwc("wallet1", "test_idor", ["pay"], [], 0) + + # Attempt to access wallet1's NWC using wallet2's credentials + async with httpx.AsyncClient() as client: + resp = await client.get( + f"http://localhost:5002/nwcprovider/api/v1/nwc/{nwc_wallet1['pubkey']}", + headers={"X-Api-Key": wallets["wallet2"]["admin_key"]}, + ) + assert resp.status_code == 500 + assert "Pubkey has no associated wallet" in resp.text + + +@pytest.mark.asyncio +async def test_sql_injection(): + """Test for SQL injection vulnerabilities in parameters""" + malicious_pubkey = "'; DROP TABLE nwc;--" + async with httpx.AsyncClient() as client: + resp = await client.put( + f"http://localhost:5002/nwcprovider/api/v1/nwc/{malicious_pubkey}", + headers={"X-Api-Key": wallets["wallet1"]["admin_key"]}, + json={"permissions": ["pay"], "description": "test"}, + ) + # Should be rejected by input validation + assert resp.status_code == 400 + + +@pytest.mark.asyncio +async def test_invalid_invoice_handling(): + """Test handling of malformed invoices""" + nwc = await create_nwc("wallet1", "test_invalid", ["pay"], [], 0) + wallet = NWCWallet(nwc["pairing"]) + await wallet.start() + + # Send invalid invoice + await wallet.send_event("pay_invoice", {"invoice": "invalid_lninvoice"}) + _, _, error = await wallet.wait_for("pay_invoice") + assert error["code"] == "INTERNAL" + + +@pytest.mark.asyncio +async def test_replay_attack(): + """Test message replay protection""" + nwc = await create_nwc("wallet1", "test_replay", ["pay", "invoice"], [], 0) + wallet = NWCWallet(nwc["pairing"]) + await wallet.start() + + # Capture valid payment request + valid_invoice = await create_valid_invoice(wallet) + await wallet.send_event("pay_invoice", {"invoice": valid_invoice}) + _, _, error = await wallet.wait_for("pay_invoice") + assert not error + + # Replay same message + await wallet.send_event("pay_invoice", {"invoice": valid_invoice}) + _, _, error = await wallet.wait_for("pay_invoice") + assert error["code"] == "PAYMENT_FAILED" + + +@pytest.mark.asyncio +async def test_budget_bypass(): + """Test budget limit enforcement""" + nwc = await create_nwc( + "wallet1", + "test_budget_bypass", + ["pay", "invoice"], + [ + { + "budget_msats": 100000, + "refresh_window": 3600, + "created_at": int(time.time()), + } + ], + 0, + ) + wallet = NWCWallet(nwc["pairing"]) + await wallet.start() + + # First payment within budget + invoice1 = await create_valid_invoice(wallet, 50000) + await wallet.send_event("pay_invoice", {"invoice": invoice1}) + _, _, error = await wallet.wait_for("pay_invoice") + assert not error + + # Attempt to exceed budget + invoice2 = await create_valid_invoice(wallet, 60000) + await wallet.send_event("pay_invoice", {"invoice": invoice2}) + _, _, error = await wallet.wait_for("pay_invoice") + assert error["code"] == "QUOTA_EXCEEDED" + + +@pytest.mark.asyncio +async def test_unauthorized_config(): + """Test unauthorized access to config endpoint""" + malicious_relay = "ws://attacker-relay.example" + + async def set_config_nwc(key: str, value: str): + async with httpx.AsyncClient() as client: + resp = await client.post( + "http://localhost:5002/nwcprovider/api/v1/config", + json={key: value}, + headers={"X-Api-Key": "lnbitsadmin"}, # Assuming admin key + ) + assert resp.status_code == 401 + + await set_config_nwc("relay", malicious_relay) + + +async def create_valid_invoice(wallet, amount=1000): + """Helper function to create valid test invoice""" + await wallet.send_event( + "make_invoice", {"amount": amount, "description": "test invoice"} + ) + result, tags, error = await wallet.wait_for("make_invoice") + if error: + raise Exception(f"Failed to create invoice: {error}") + return result["invoice"] diff --git a/tests/unit/test_nwcp.py b/tests/unit/test_nwcp.py index 8ee0b75..f9a650e 100644 --- a/tests/unit/test_nwcp.py +++ b/tests/unit/test_nwcp.py @@ -29,8 +29,7 @@ def nwc_service_provider2(): ) -@pytest.mark.asyncio -async def test_supported_methods(nwc_service_provider): +def test_supported_methods(nwc_service_provider): def make_invoice(provider, pubkey, content): return "invoice" @@ -39,8 +38,7 @@ def make_invoice(provider, pubkey, content): assert s == ["make_invoice"] -@pytest.mark.asyncio -async def test_encrytdecrypt(nwc_service_provider, nwc_service_provider2): +def test_encrytdecrypt(nwc_service_provider, nwc_service_provider2): content = "Hello World" expected_enc = "qVurNVISSl/9CfREIhk5Lg==?iv=QpCo5dI9gUcoLsSMLA7o7Q==" enc_a = nwc_service_provider._encrypt_content( @@ -63,8 +61,7 @@ async def test_encrytdecrypt(nwc_service_provider, nwc_service_provider2): assert enc_b == expected_enc -@pytest.mark.asyncio -async def test_signverify(nwc_service_provider, nwc_service_provider2): +def test_signverify(nwc_service_provider, nwc_service_provider2): # Random content content = "" for _ in range(100): diff --git a/toc.md b/toc.md new file mode 100644 index 0000000..baa0342 --- /dev/null +++ b/toc.md @@ -0,0 +1,29 @@ +# Terms and Conditions for LNbits Extension + +## 1. Acceptance of Terms + +By installing and using the LNbits extension ("Extension"), you agree to be bound by these terms and conditions ("Terms"). If you do not agree to these Terms, do not use the Extension. + +## 2. License + +The Extension is free and open-source software, released under [specify the FOSS license here, e.g., GPL-3.0, MIT, etc.]. You are permitted to use, copy, modify, and distribute the Extension under the terms of that license. + +## 3. No Warranty + +The Extension is provided "as is" and with all faults, and the developer expressly disclaims all warranties of any kind, whether express, implied, statutory, or otherwise, including but not limited to warranties of merchantability, fitness for a particular purpose, non-infringement, and any warranties arising out of course of dealing or usage of trade. No advice or information, whether oral or written, obtained from the developer or elsewhere will create any warranty not expressly stated in this Terms. + +## 4. Limitation of Liability + +In no event will the developer be liable to you or any third party for any direct, indirect, incidental, special, consequential, or punitive damages, including lost profit, lost revenue, loss of data, or other damages arising out of or in connection with your use of the Extension, even if the developer has been advised of the possibility of such damages. The foregoing limitation of liability shall apply to the fullest extent permitted by law in the applicable jurisdiction. + +## 5. Modification of Terms + +The developer reserves the right to modify these Terms at any time. You are advised to review these Terms periodically for any changes. Changes to these Terms are effective when they are posted on the appropriate location within or associated with the Extension. + +## 6. General Provisions + +If any provision of these Terms is held to be invalid or unenforceable, that provision will be enforced to the maximum extent permissible, and the other provisions of these Terms will remain in full force and effect. These Terms constitute the entire agreement between you and the developer regarding the use of the Extension. + +## 7. Contact Information + +If you have any questions about these Terms, please contact the developer at [developer's contact information]. diff --git a/views.py b/views.py index fb81181..dad32a6 100644 --- a/views.py +++ b/views.py @@ -4,23 +4,22 @@ from lnbits.helpers import template_renderer from starlette.responses import HTMLResponse +nwcprovider_router = APIRouter() + def nwcprovider_renderer(): return template_renderer(["nwcprovider/templates"]) -nwcprovider_router = APIRouter() - - @nwcprovider_router.get("/", response_class=HTMLResponse) async def index(request: Request, user: User = Depends(check_user_exists)): return nwcprovider_renderer().TemplateResponse( - "nwcprovider/index.html", {"request": request, "user": user.dict()} + "nwcprovider/index.html", {"request": request, "user": user.json()} ) @nwcprovider_router.get("/admin", response_class=HTMLResponse) async def admin(request: Request, user: User = Depends(check_admin)): return nwcprovider_renderer().TemplateResponse( - "nwcprovider/admin.html", {"request": request, "user": user.dict()} + "nwcprovider/admin.html", {"request": request, "user": user.json()} ) diff --git a/views_api.py b/views_api.py index 3db81a6..c29c60c 100644 --- a/views_api.py +++ b/views_api.py @@ -17,7 +17,21 @@ get_wallet_nwcs, set_config_nwc, ) -from .models import NWCGetResponse, NWCRegistrationRequest +from .models import ( + CreateNWCKey, + DeleteNWC, + GetBudgetsNWC, + GetNWC, + GetWalletNWC, + NWCGetResponse, + NWCRegistrationRequest, +) +from .paranoia import ( + assert_boolean, + assert_sane_string, + assert_valid_pubkey, + assert_valid_wallet_id, +) from .permission import nwc_permissions nwcprovider_api_router = APIRouter() @@ -25,10 +39,7 @@ # Get supported permissions @nwcprovider_api_router.get("/api/v1/permissions", status_code=HTTPStatus.OK) -async def api_get_permissions( - req: Request, - wallet: WalletTypeInfo = Depends(require_admin_key), -) -> Dict: +async def api_get_permissions() -> Dict: return nwc_permissions @@ -37,17 +48,26 @@ async def api_get_permissions( "/api/v1/nwc", status_code=HTTPStatus.OK, response_model=List[NWCGetResponse] ) async def api_get_nwcs( - req: Request, include_expired: bool = False, calculate_spent_budget: bool = False, wallet: WalletTypeInfo = Depends(require_admin_key), ): - wallet_id = wallet.wallet.id - nwcs = await get_wallet_nwcs(wallet_id, include_expired) + + # hardening # + assert_valid_wallet_id(wallet_id) + assert_boolean(include_expired) + assert_boolean(calculate_spent_budget) + # ## # + + wallet_nwcs = GetWalletNWC(wallet=wallet_id, include_expired=include_expired) + nwcs = await get_wallet_nwcs(wallet_nwcs) out = [] for nwc in nwcs: - budgets = await get_budgets_nwc(nwc.pubkey, calculate_spent_budget) + budgets_nwc = GetBudgetsNWC( + pubkey=nwc.pubkey, calculate_spent=calculate_spent_budget + ) + budgets = await get_budgets_nwc(budgets_nwc) res = NWCGetResponse(data=nwc, budgets=budgets) out.append(res) return out @@ -58,16 +78,26 @@ async def api_get_nwcs( "/api/v1/nwc/{pubkey}", status_code=HTTPStatus.OK, response_model=NWCGetResponse ) async def api_get_nwc( - req: Request, pubkey: str, - include_expired: Optional[bool] = False, + include_expired: bool = False, wallet: WalletTypeInfo = Depends(require_admin_key), ) -> NWCGetResponse: wallet_id = wallet.wallet.id - nwc = await get_nwc(pubkey, wallet_id, include_expired) + + # hardening # + assert_valid_pubkey(pubkey) + assert_boolean(include_expired) + assert_valid_wallet_id(wallet_id) + # ## # + + nwc = await get_nwc( + GetNWC(pubkey=pubkey, wallet=wallet_id, include_expired=include_expired) + ) if not nwc: raise Exception("Pubkey has no associated wallet") - res = NWCGetResponse(data=nwc, budgets=await get_budgets_nwc(pubkey)) + res = NWCGetResponse( + data=nwc, budgets=await get_budgets_nwc(GetBudgetsNWC(pubkey=pubkey)) + ) return res @@ -76,6 +106,11 @@ async def api_get_nwc( "/api/v1/pairing/{secret}", status_code=HTTPStatus.OK, response_model=str ) async def api_get_pairing_url(req: Request, secret: str) -> str: + + # hardening # + assert_sane_string(secret) + # ## # + pprivkey: Optional[str] = await get_config_nwc("provider_key") if not pprivkey: raise Exception("Extension is not configured") @@ -115,21 +150,28 @@ async def api_get_pairing_url(req: Request, secret: str) -> str: response_model=NWCGetResponse, ) async def api_register_nwc( - req: Request, pubkey: str, - registration_data: NWCRegistrationRequest, # Use the Pydantic model here + data: NWCRegistrationRequest, wallet: WalletTypeInfo = Depends(require_admin_key), ): wallet_id = wallet.wallet.id + + # hardening # + assert_valid_pubkey(pubkey) + assert_valid_wallet_id(wallet_id) + # ## # + nwc = await create_nwc( - pubkey, - wallet_id, - registration_data.description, - registration_data.expires_at, - registration_data.permissions, - registration_data.budgets, + CreateNWCKey( + pubkey=pubkey, + wallet=wallet_id, + description=data.description, + expires_at=data.expires_at, + permissions=data.permissions, + budgets=data.budgets, + ) ) - budgets = await get_budgets_nwc(pubkey) + budgets = await get_budgets_nwc(GetBudgetsNWC(pubkey=pubkey)) res = NWCGetResponse(data=nwc, budgets=budgets) return res @@ -137,10 +179,16 @@ async def api_register_nwc( # Delete a nwc key @nwcprovider_api_router.delete("/api/v1/nwc/{pubkey}", status_code=HTTPStatus.OK) async def api_delete_nwc( - req: Request, pubkey: str, wallet: WalletTypeInfo = Depends(require_admin_key) + pubkey: str, wallet: WalletTypeInfo = Depends(require_admin_key) ): wallet_id = wallet.wallet.id - await delete_nwc(pubkey, wallet_id) + + # hardening # + assert_valid_pubkey(pubkey) + assert_valid_wallet_id(wallet_id) + # ## # + + await delete_nwc(DeleteNWC(pubkey=pubkey, wallet=wallet_id)) return JSONResponse(content={"message": f"NWC key {pubkey} deleted successfully."}) @@ -148,9 +196,7 @@ async def api_delete_nwc( @nwcprovider_api_router.get( "/api/v1/config", status_code=HTTPStatus.OK, dependencies=[Depends(check_admin)] ) -async def api_get_all_config_nwc( - req: Request, -): +async def api_get_all_config_nwc(): config = await get_all_config_nwc() return config @@ -161,7 +207,7 @@ async def api_get_all_config_nwc( status_code=HTTPStatus.OK, dependencies=[Depends(check_admin)], ) -async def api_get_config_nwc(req: Request, key: str): +async def api_get_config_nwc(key: str): config = await get_config_nwc(key) out = {} out[key] = config @@ -174,6 +220,13 @@ async def api_get_config_nwc(req: Request, key: str): ) async def api_set_config_nwc(req: Request): data = await req.json() + + # hardening # + for key, value in data.items(): + assert_sane_string(key) + assert_sane_string(value) + # ## # + for key, value in data.items(): await set_config_nwc(key, value) - return await api_get_all_config_nwc(req) + return await api_get_all_config_nwc() From 8a426433705d54312fc15a85a92809d7ad731622 Mon Sep 17 00:00:00 2001 From: 21M4TW <21m4tw@proton.me> Date: Thu, 5 Jun 2025 19:37:07 -0400 Subject: [PATCH 02/13] -Adding support for a new make_offer command --- permission.py | 5 +++++ tasks.py | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/permission.py b/permission.py index 9caf17b..b329465 100644 --- a/permission.py +++ b/permission.py @@ -9,6 +9,11 @@ ], "default": True, }, + "offer": { + "name": "Create offer", + "methods": ["make_offer"], + "default": True, + }, "invoice": { "name": "Create invoices", "methods": ["make_invoice"], diff --git a/tasks.py b/tasks.py index d06a80f..dac2b7b 100644 --- a/tasks.py +++ b/tasks.py @@ -8,6 +8,7 @@ from lnbits.core.models import Payment from lnbits.core.services import ( check_transaction_status, + create_offer, create_invoice, pay_invoice, ) @@ -227,6 +228,57 @@ async def _on_multi_pay_invoice( return results +async def _on_make_offer( + sp: NWCServiceProvider, pubkey: str, payload: Dict +) -> List[Tuple[Optional[Dict], Optional[Dict], List]]: + + # hardening # + assert_valid_pubkey(pubkey) + # ## # + + nwc = await get_nwc(GetNWC(pubkey=pubkey, refresh_last_used=True)) + error = await _check(nwc, "make_offer") + if error: + return [(None, error, [])] + if not nwc: + raise Exception("Pubkey has no associated wallet") + params = payload.get("params", {}) + amount_msats = params.get("amount", None) + memo = params.get("memo", "") + absolute_expiry = params.get("absolute_expiry", None) + single_use = params.get("single_use", False) + + # hardening # + if amount_msats is not None: + assert_valid_msats(amount_msats) + if memo: + assert_sane_string(memo) + if absolute_expiry: + assert_valid_expiration_seconds(absolute_expiry) + assert_boolean(single_use) + # ## # + + offer = await create_offer( + wallet_id=nwc.wallet, + amount_sat=amount_msats / 1000 if amount_msats else None, + memo=memo, + absolute_expiry=absolute_expiry, + single_use=single_use, + ) + + res = { + "bolt12": offer.bolt12, + "memo": offer.memo, + "amount": offer.amount, + "offer_id": offer.offer_id, + "active": offer.active, + "single_use": offer.single_use, + "created_at": int(offer.created_at.timestamp()), + "metadata": {}, + } + return [(res, None, [])] + + async def _on_make_invoice( sp: NWCServiceProvider, pubkey: str, payload: Dict ) -> List[Tuple[Optional[Dict], Optional[Dict], List]]: @@ -503,6 +555,7 @@ async def handle_nwc(): nwcsp = NWCServiceProvider(priv_key, relay, handle_missed_events) nwcsp.add_request_listener("pay_invoice", _on_pay_invoice) nwcsp.add_request_listener("multi_pay_invoice", _on_multi_pay_invoice) + nwcsp.add_request_listener("make_offer", _on_make_offer) nwcsp.add_request_listener("make_invoice", _on_make_invoice) nwcsp.add_request_listener("lookup_invoice", _on_lookup_invoice) nwcsp.add_request_listener("list_transactions", _on_list_transactions) From 567397503bdd2efc17bbbc6a330910daecb15ff3 Mon Sep 17 00:00:00 2001 From: 21M4TW <21m4tw@proton.me> Date: Thu, 5 Jun 2025 23:07:30 -0400 Subject: [PATCH 03/13] -Adding lookup_offer command --- permission.py | 5 +++++ tasks.py | 45 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/permission.py b/permission.py index b329465..5ee3d52 100644 --- a/permission.py +++ b/permission.py @@ -14,6 +14,11 @@ "methods": ["make_offer"], "default": True, }, + "lookup_offer": { + "name": "Lookup status of offer", + "methods": ["lookup_offer"], + "default": True, + }, "invoice": { "name": "Create invoices", "methods": ["make_invoice"], diff --git a/tasks.py b/tasks.py index dac2b7b..328f5a0 100644 --- a/tasks.py +++ b/tasks.py @@ -4,7 +4,7 @@ from typing import Any, Dict, List, Optional, Tuple from bolt11 import decode as bolt11_decode -from lnbits.core.crud import get_payments, get_wallet, get_wallet_payment +from lnbits.core.crud import get_standalone_offer, get_payments, get_wallet, get_wallet_payment from lnbits.core.models import Payment from lnbits.core.services import ( check_transaction_status, @@ -279,6 +279,48 @@ async def _on_make_offer( return [(res, None, [])] +async def _on_lookup_offer( + sp: NWCServiceProvider, pubkey: str, payload: Dict +) -> List[Tuple[Optional[Dict], Optional[Dict], List]]: + + # hardening # + assert_valid_pubkey(pubkey) + # ## # + + nwc = await get_nwc(GetNWC(pubkey=pubkey, refresh_last_used=True)) + error = await _check(nwc, "lookup_offer") + if error: + return [(None, error, [])] + if not nwc: + raise Exception("Pubkey has no associated wallet") + params = payload.get("params", {}) + offer_id = params.get("offer_id", None) + # Ensure offer_id is provided + if not offer_id: + raise Exception("Missing offer_id") + + # hardening # + assert_valid_sha256(offer_id) + # ## # + + offer = await get_standalone_offer(offer_id = offer_id, wallet_id = nwc.wallet) + + if not offer: + raise Exception("Offer not found") + + res = { + "bolt12": offer.bolt12, + "memo": offer.memo, + "amount": offer.amount, + "offer_id": offer.offer_id, + "active": offer.active, + "single_use": offer.single_use, + "created_at": int(offer.created_at.timestamp()), + "metadata": {}, + } + return [(res, None, [])] + + async def _on_make_invoice( sp: NWCServiceProvider, pubkey: str, payload: Dict ) -> List[Tuple[Optional[Dict], Optional[Dict], List]]: @@ -556,6 +598,7 @@ async def handle_nwc(): nwcsp.add_request_listener("pay_invoice", _on_pay_invoice) nwcsp.add_request_listener("multi_pay_invoice", _on_multi_pay_invoice) nwcsp.add_request_listener("make_offer", _on_make_offer) + nwcsp.add_request_listener("lookup_offer", _on_lookup_offer) nwcsp.add_request_listener("make_invoice", _on_make_invoice) nwcsp.add_request_listener("lookup_invoice", _on_lookup_invoice) nwcsp.add_request_listener("list_transactions", _on_list_transactions) From 7ddba41e61a315c243c9f46cfee1c35fa75ef3d8 Mon Sep 17 00:00:00 2001 From: 21M4TW <21m4tw@proton.me> Date: Sat, 7 Jun 2025 08:25:46 -0400 Subject: [PATCH 04/13] -Adding list_offers command --- nwcp.py | 2 ++ permission.py | 5 ++++ tasks.py | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 84 insertions(+), 1 deletion(-) diff --git a/nwcp.py b/nwcp.py index 4a5023a..b0b842d 100644 --- a/nwcp.py +++ b/nwcp.py @@ -219,6 +219,7 @@ async def _send(self, data: List[Any]): return await self._wait_for_connection() # ensure the connection is established tx = self._json_dumps(data) + logger.debug(tx) await self.ws.send(tx) def _get_new_subid(self) -> str: @@ -493,6 +494,7 @@ async def _connect_to_relay(self): ): # receive messages until the instance is shutting down try: reply = await ws.recv() + logger.debug(reply) if isinstance(reply, bytes): reply = reply.decode("utf-8") await self._on_message(ws, reply) diff --git a/permission.py b/permission.py index 5ee3d52..00b7f53 100644 --- a/permission.py +++ b/permission.py @@ -19,6 +19,11 @@ "methods": ["lookup_offer"], "default": True, }, + "list_offers": { + "name": "Read list of offers", + "methods": ["list_offers"], + "default": True, + }, "invoice": { "name": "Create invoices", "methods": ["make_invoice"], diff --git a/tasks.py b/tasks.py index 328f5a0..3e5971c 100644 --- a/tasks.py +++ b/tasks.py @@ -4,7 +4,7 @@ from typing import Any, Dict, List, Optional, Tuple from bolt11 import decode as bolt11_decode -from lnbits.core.crud import get_standalone_offer, get_payments, get_wallet, get_wallet_payment +from lnbits.core.crud import get_standalone_offer, get_offers, get_payments, get_wallet, get_wallet_payment from lnbits.core.models import Payment from lnbits.core.services import ( check_transaction_status, @@ -273,6 +273,7 @@ async def _on_make_offer( "offer_id": offer.offer_id, "active": offer.active, "single_use": offer.single_use, + "used": offer.used, "created_at": int(offer.created_at.timestamp()), "metadata": {}, } @@ -315,12 +316,86 @@ async def _on_lookup_offer( "offer_id": offer.offer_id, "active": offer.active, "single_use": offer.single_use, + "used": offer.used, "created_at": int(offer.created_at.timestamp()), "metadata": {}, } return [(res, None, [])] +async def _on_list_offers( + sp: NWCServiceProvider, pubkey: str, payload: Dict +) -> List[Tuple[Optional[Dict], Optional[Dict], List]]: + # hardening # + assert_valid_pubkey(pubkey) + # ## # + + nwc = await get_nwc(GetNWC(pubkey=pubkey, refresh_last_used=True)) + error = await _check(nwc, "list_offers") + if error: + return [(None, error, [])] + if not nwc: + raise Exception("Pubkey has no associated wallet") + params = payload.get("params", {}) + tfrom = params.get("from", 0) + tto = params.get("to", int(time.time())) + limit = params.get("limit", 10) + offset = params.get("offset", 0) + active = params.get("active", None) + single_use = params.get("single_use", None) + used = params.get("used", None) + + # hardening # + assert_valid_positive_int(tfrom) + assert_valid_positive_int(tto) + assert_valid_positive_int(limit) + assert_valid_positive_int(offset) + + if active is not None: + assert_boolean(active_only) + + if single_use is not None: + assert_boolean(single_use) + + if used is not None: + assert_boolean(used) + # ## # + + values = [] + filters: Filters = Filters() + filters.where(["created_at <= ?"]) + values.append(tto) + filters.values(values) + history = await get_offers( + wallet_id=nwc.wallet, + active=active, + single_use=single_use, + used=used, + since=tfrom, + filters=filters, + limit=limit, + offset=offset, + ) + offers: List[Dict] = [] + o: Offer + for o in history: + offers.append( + { + "bolt12": o.bolt12, + "memo": o.memo, + "amount": o.amount, + "offer_id": o.offer_id, + "active": o.active, + "single_use": o.single_use, + "used": o.used, + "created_at": int(o.created_at.timestamp()), + "metadata": {}, + } + ) + # await log_nwc(pubkey, payload) + return [({"offers": offers}, None, [])] + + async def _on_make_invoice( sp: NWCServiceProvider, pubkey: str, payload: Dict ) -> List[Tuple[Optional[Dict], Optional[Dict], List]]: @@ -599,6 +674,7 @@ async def handle_nwc(): nwcsp.add_request_listener("multi_pay_invoice", _on_multi_pay_invoice) nwcsp.add_request_listener("make_offer", _on_make_offer) nwcsp.add_request_listener("lookup_offer", _on_lookup_offer) + nwcsp.add_request_listener("list_offers", _on_list_offers) nwcsp.add_request_listener("make_invoice", _on_make_invoice) nwcsp.add_request_listener("lookup_invoice", _on_lookup_invoice) nwcsp.add_request_listener("list_transactions", _on_list_transactions) From ac1877c83208bb778b9f951047696d8dd4a3db56 Mon Sep 17 00:00:00 2001 From: 21M4TW <21m4tw@proton.me> Date: Sat, 7 Jun 2025 08:35:25 -0400 Subject: [PATCH 05/13] -Two issues identified with the list_transactions command: -Was accessing the arguments from payload instead of from params -Was using "to" instead of "until" defined in NIP-47 --- tasks.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/tasks.py b/tasks.py index 3e5971c..0eccbb2 100644 --- a/tasks.py +++ b/tasks.py @@ -542,16 +542,17 @@ async def _on_list_transactions( return [(None, error, [])] if not nwc: raise Exception("Pubkey has no associated wallet") - tfrom = payload.get("from", 0) - tto = payload.get("to", int(time.time())) - limit = payload.get("limit", 10) - offset = payload.get("offset", 0) - unpaid = payload.get("unpaid", False) - tx_type = payload.get("type", "") + params = payload.get("params", 0) + tfrom = params.get("from", 0) + tuntil = params.get("until", int(time.time())) + limit = params.get("limit", 10) + offset = params.get("offset", 0) + unpaid = params.get("unpaid", False) + tx_type = params.get("type", "") # hardening # assert_valid_positive_int(tfrom) - assert_valid_positive_int(tto) + assert_valid_positive_int(tuntil) assert_valid_positive_int(limit) assert_valid_positive_int(offset) assert_boolean(unpaid) @@ -561,7 +562,7 @@ async def _on_list_transactions( values = [] filters: Filters = Filters() filters.where(["time <= ?"]) - values.append(tto) + values.append(tuntil) filters.values(values) history = await get_payments( wallet_id=nwc.wallet, From 231322a9e8ffa8fb1f53e7b5e12d6fabbe5adce4 Mon Sep 17 00:00:00 2001 From: 21M4TW <21m4tw@proton.me> Date: Sat, 7 Jun 2025 08:56:22 -0400 Subject: [PATCH 06/13] list_offers: Renamed 'to' as 'until' --- tasks.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tasks.py b/tasks.py index 0eccbb2..d21e860 100644 --- a/tasks.py +++ b/tasks.py @@ -338,7 +338,7 @@ async def _on_list_offers( raise Exception("Pubkey has no associated wallet") params = payload.get("params", {}) tfrom = params.get("from", 0) - tto = params.get("to", int(time.time())) + tuntil = params.get("until", int(time.time())) limit = params.get("limit", 10) offset = params.get("offset", 0) active = params.get("active", None) @@ -347,7 +347,7 @@ async def _on_list_offers( # hardening # assert_valid_positive_int(tfrom) - assert_valid_positive_int(tto) + assert_valid_positive_int(tuntil) assert_valid_positive_int(limit) assert_valid_positive_int(offset) @@ -364,7 +364,7 @@ async def _on_list_offers( values = [] filters: Filters = Filters() filters.where(["created_at <= ?"]) - values.append(tto) + values.append(tuntil) filters.values(values) history = await get_offers( wallet_id=nwc.wallet, From 8ba23780ef241f1105dc03085f4b121e8896ce4b Mon Sep 17 00:00:00 2001 From: 21M4TW <21m4tw@proton.me> Date: Sat, 7 Jun 2025 11:35:40 -0400 Subject: [PATCH 07/13] -Creating _offer_to_dict function to handle Offer object conversion --- tasks.py | 54 ++++++++++++++++-------------------------------------- 1 file changed, 16 insertions(+), 38 deletions(-) diff --git a/tasks.py b/tasks.py index d21e860..bf69597 100644 --- a/tasks.py +++ b/tasks.py @@ -5,7 +5,7 @@ from bolt11 import decode as bolt11_decode from lnbits.core.crud import get_standalone_offer, get_offers, get_payments, get_wallet, get_wallet_payment -from lnbits.core.models import Payment +from lnbits.core.models import Offer, Payment from lnbits.core.services import ( check_transaction_status, create_offer, @@ -227,6 +227,18 @@ async def _on_multi_pay_invoice( # await log_nwc(pubkey, payload) return results +def _offer_to_dict(offer: Offer) -> Dict: + return { + "bolt12": offer.bolt12, + "memo": offer.memo, + "amount": offer.amount, + "offer_id": offer.offer_id, + "active": offer.active, + "single_use": offer.single_use, + "used": offer.used, + "created_at": int(offer.created_at.timestamp()), + "metadata": {}, + } async def _on_make_offer( sp: NWCServiceProvider, pubkey: str, payload: Dict @@ -266,18 +278,7 @@ async def _on_make_offer( single_use=single_use, ) - res = { - "bolt12": offer.bolt12, - "memo": offer.memo, - "amount": offer.amount, - "offer_id": offer.offer_id, - "active": offer.active, - "single_use": offer.single_use, - "used": offer.used, - "created_at": int(offer.created_at.timestamp()), - "metadata": {}, - } - return [(res, None, [])] + return [(_offer_to_dict(offer), None, [])] async def _on_lookup_offer( @@ -309,18 +310,7 @@ async def _on_lookup_offer( if not offer: raise Exception("Offer not found") - res = { - "bolt12": offer.bolt12, - "memo": offer.memo, - "amount": offer.amount, - "offer_id": offer.offer_id, - "active": offer.active, - "single_use": offer.single_use, - "used": offer.used, - "created_at": int(offer.created_at.timestamp()), - "metadata": {}, - } - return [(res, None, [])] + return [(_offer_to_dict(res), None, [])] async def _on_list_offers( @@ -379,19 +369,7 @@ async def _on_list_offers( offers: List[Dict] = [] o: Offer for o in history: - offers.append( - { - "bolt12": o.bolt12, - "memo": o.memo, - "amount": o.amount, - "offer_id": o.offer_id, - "active": o.active, - "single_use": o.single_use, - "used": o.used, - "created_at": int(o.created_at.timestamp()), - "metadata": {}, - } - ) + offers.append(_offer_to_dict(o)) # await log_nwc(pubkey, payload) return [({"offers": offers}, None, [])] From 0565356b307f456b2c80c0bde756a1fb9f545ece Mon Sep 17 00:00:00 2001 From: 21M4TW <21m4tw@proton.me> Date: Sat, 7 Jun 2025 21:13:17 -0400 Subject: [PATCH 08/13] -Adding enable_offer and disable_offer commands. -Improving _offer_to_dict function --- permission.py | 5 +++ tasks.py | 90 +++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 92 insertions(+), 3 deletions(-) diff --git a/permission.py b/permission.py index 00b7f53..033a307 100644 --- a/permission.py +++ b/permission.py @@ -19,6 +19,11 @@ "methods": ["lookup_offer"], "default": True, }, + "enable_disable_offer": { + "name": "Enabling/disabling an offer", + "methods": ["enable_offer", "disable_offer"], + "default": True, + }, "list_offers": { "name": "Read list of offers", "methods": ["list_offers"], diff --git a/tasks.py b/tasks.py index bf69597..6f544be 100644 --- a/tasks.py +++ b/tasks.py @@ -9,6 +9,8 @@ from lnbits.core.services import ( check_transaction_status, create_offer, + enable_offer, + disable_offer, create_invoice, pay_invoice, ) @@ -228,7 +230,7 @@ async def _on_multi_pay_invoice( return results def _offer_to_dict(offer: Offer) -> Dict: - return { + res = { "bolt12": offer.bolt12, "memo": offer.memo, "amount": offer.amount, @@ -237,9 +239,15 @@ def _offer_to_dict(offer: Offer) -> Dict: "single_use": offer.single_use, "used": offer.used, "created_at": int(offer.created_at.timestamp()), - "metadata": {}, + "updated_at": int(offer.updated_at.timestamp()), } + if(offer.expiry is not None): + res["expires_at"] = int(offer.expiry.timestamp()) + + res["metadata"] = {} + return res + async def _on_make_offer( sp: NWCServiceProvider, pubkey: str, payload: Dict ) -> List[Tuple[Optional[Dict], Optional[Dict], List]]: @@ -310,7 +318,81 @@ async def _on_lookup_offer( if not offer: raise Exception("Offer not found") - return [(_offer_to_dict(res), None, [])] + return [(_offer_to_dict(offer), None, [])] + + +async def _on_enable_offer( + sp: NWCServiceProvider, pubkey: str, payload: Dict +) -> List[Tuple[Optional[Dict], Optional[Dict], List]]: + + # hardening # + assert_valid_pubkey(pubkey) + # ## # + + nwc = await get_nwc(GetNWC(pubkey=pubkey, refresh_last_used=True)) + error = await _check(nwc, "enable_offer") + if error: + return [(None, error, [])] + if not nwc: + raise Exception("Pubkey has no associated wallet") + params = payload.get("params", {}) + offer_id = params.get("offer_id", None) + # Ensure offer_id is provided + if not offer_id: + raise Exception("Missing offer_id") + + # hardening # + assert_valid_sha256(offer_id) + # ## # + + result = await enable_offer(wallet_id = nwc.wallet, offer_id = offer_id) + + if result is None: + raise Exception("Offer not found") + + res = { + "offer_id": offer_id, + "active": result + } + + return [(res, None, [])] + + +async def _on_disable_offer( + sp: NWCServiceProvider, pubkey: str, payload: Dict +) -> List[Tuple[Optional[Dict], Optional[Dict], List]]: + + # hardening # + assert_valid_pubkey(pubkey) + # ## # + + nwc = await get_nwc(GetNWC(pubkey=pubkey, refresh_last_used=True)) + error = await _check(nwc, "disable_offer") + if error: + return [(None, error, [])] + if not nwc: + raise Exception("Pubkey has no associated wallet") + params = payload.get("params", {}) + offer_id = params.get("offer_id", None) + # Ensure offer_id is provided + if not offer_id: + raise Exception("Missing offer_id") + + # hardening # + assert_valid_sha256(offer_id) + # ## # + + result = await disable_offer(wallet_id = nwc.wallet, offer_id = offer_id) + + if result is None: + raise Exception("Offer not found") + + res = { + "offer_id": offer_id, + "active": result + } + + return [(res, None, [])] async def _on_list_offers( @@ -653,6 +735,8 @@ async def handle_nwc(): nwcsp.add_request_listener("multi_pay_invoice", _on_multi_pay_invoice) nwcsp.add_request_listener("make_offer", _on_make_offer) nwcsp.add_request_listener("lookup_offer", _on_lookup_offer) + nwcsp.add_request_listener("enable_offer", _on_enable_offer) + nwcsp.add_request_listener("disable_offer", _on_disable_offer) nwcsp.add_request_listener("list_offers", _on_list_offers) nwcsp.add_request_listener("make_invoice", _on_make_invoice) nwcsp.add_request_listener("lookup_invoice", _on_lookup_invoice) From 35ce72ad5dbfe5c07758af5ba1a831318679276f Mon Sep 17 00:00:00 2001 From: 21M4TW <21m4tw@proton.me> Date: Sat, 7 Jun 2025 23:39:59 -0400 Subject: [PATCH 09/13] -Adding fetch_invoice command --- paranoia.py | 7 +++++ permission.py | 1 + tasks.py | 74 ++++++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 78 insertions(+), 4 deletions(-) diff --git a/paranoia.py b/paranoia.py index 5ebca7c..5907829 100644 --- a/paranoia.py +++ b/paranoia.py @@ -162,6 +162,13 @@ def assert_valid_bolt11(invoice: str): assert_printable(invoice) +# Check if string is a valid bolt12 string +def assert_valid_bolt12(bolt12: str): + if not ENABLE_HARDENING: + return + assert_printable(bolt12) + + # Check if boolean def assert_boolean(v: bool): if not ENABLE_HARDENING: diff --git a/permission.py b/permission.py index 033a307..165da01 100644 --- a/permission.py +++ b/permission.py @@ -2,6 +2,7 @@ "pay": { "name": "Send payments", "methods": [ + "fetch_invoice", "multi_pay_invoice", "pay_invoice", "pay_keysend", diff --git a/tasks.py b/tasks.py index 6f544be..ba8ad37 100644 --- a/tasks.py +++ b/tasks.py @@ -11,13 +11,15 @@ create_offer, enable_offer, disable_offer, + fetch_invoice, create_invoice, pay_invoice, ) from lnbits.db import Filters from lnbits.exceptions import PaymentError from lnbits.settings import settings -from lnbits.wallets.base import PaymentStatus +from lnbits.wallets.base import PaymentStatus, InvoiceData +from lnbits.wallets import get_funding_source from loguru import logger from .crud import get_config_nwc, get_nwc, tracked_spend_nwc @@ -28,6 +30,7 @@ assert_boolean, assert_sane_string, assert_valid_bolt11, + assert_valid_bolt12, assert_valid_expiration_seconds, assert_valid_msats, assert_valid_positive_int, @@ -231,7 +234,7 @@ async def _on_multi_pay_invoice( def _offer_to_dict(offer: Offer) -> Dict: res = { - "bolt12": offer.bolt12, + "offer": offer.bolt12, "memo": offer.memo, "amount": offer.amount, "offer_id": offer.offer_id, @@ -242,7 +245,7 @@ def _offer_to_dict(offer: Offer) -> Dict: "updated_at": int(offer.updated_at.timestamp()), } - if(offer.expiry is not None): + if offer.expiry is not None: res["expires_at"] = int(offer.expiry.timestamp()) res["metadata"] = {} @@ -280,7 +283,7 @@ async def _on_make_offer( offer = await create_offer( wallet_id=nwc.wallet, - amount_sat=amount_msats / 1000 if amount_msats else None, + amount_sat=amount_msats * 0.001 if amount_msats is not None else None, memo=memo, absolute_expiry=absolute_expiry, single_use=single_use, @@ -456,6 +459,68 @@ async def _on_list_offers( return [({"offers": offers}, None, [])] +async def _on_fetch_invoice( + sp: NWCServiceProvider, pubkey: str, payload: Dict +) -> List[Tuple[Optional[Dict], Optional[Dict], List]]: + + # hardening # + assert_valid_pubkey(pubkey) + # ## # + + nwc = await get_nwc(GetNWC(pubkey=pubkey, refresh_last_used=True)) + error = await _check(nwc, "fetch_invoice") + if error: + return [(None, error, [])] + if not nwc: + raise Exception("Pubkey has no associated wallet") + logger.debug(payload) + params = payload.get("params", {}) + offer = params.get("offer", None) + # Ensure offer_id is provided + if not offer: + raise Exception("Missing offer") + amount_msat = params.get("amount", None) + payer_note = params.get("payer_note", None) + + # hardening # + assert_valid_bolt12(offer) + if amount_msat is not None: + assert_valid_msats(amount_msat) + if payer_note is not None: + assert_sane_string(payer_note) + # ## # + + bolt12 = await fetch_invoice( + wallet_id = nwc.wallet, + offer = offer, + amount = amount_msat * 0.001 if amount_msat is not None else None, + payer_note = payer_note) + + funding_source = get_funding_source() + + invoice = await funding_source.decode_invoice(bolt12) + + res = { + "invoice": bolt12, + } + + if invoice.description: + res["description"] = invoice.description + if invoice.description_hash: + res["description_hash"] = invoice.description_hash + if invoice.payer_note: + res["payer_note"] = invoice.payer_note + res["payment_hash"] = invoice.payment_hash + if invoice.amount_msat: + res["amount"] = invoice.amount_msat + if invoice.offer_id: + res["offer_id"] = invoice.offer_id + res["created_at"] = int(invoice.invoice_created_at) + if invoice.invoice_relative_expiry: + res["expires_at"] = int(invoice.invoice_created_at) + int(invoice.invoice_relative_expiry) + return [(res, None, [])] + + async def _on_make_invoice( sp: NWCServiceProvider, pubkey: str, payload: Dict ) -> List[Tuple[Optional[Dict], Optional[Dict], List]]: @@ -738,6 +803,7 @@ async def handle_nwc(): nwcsp.add_request_listener("enable_offer", _on_enable_offer) nwcsp.add_request_listener("disable_offer", _on_disable_offer) nwcsp.add_request_listener("list_offers", _on_list_offers) + nwcsp.add_request_listener("fetch_invoice", _on_fetch_invoice) nwcsp.add_request_listener("make_invoice", _on_make_invoice) nwcsp.add_request_listener("lookup_invoice", _on_lookup_invoice) nwcsp.add_request_listener("list_transactions", _on_list_transactions) From 2c15cdf2c3021ce820c835111f092aa885b74c5c Mon Sep 17 00:00:00 2001 From: 21M4TW <21m4tw@proton.me> Date: Sun, 8 Jun 2025 21:55:23 -0400 Subject: [PATCH 10/13] -Add partial bolt12 support to lookup_invoice. Still uses fake bolt11 string for bolt12 invoices. --- tasks.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/tasks.py b/tasks.py index ba8ad37..9a9ae91 100644 --- a/tasks.py +++ b/tasks.py @@ -473,7 +473,6 @@ async def _on_fetch_invoice( return [(None, error, [])] if not nwc: raise Exception("Pubkey has no associated wallet") - logger.debug(payload) params = payload.get("params", {}) offer = params.get("offer", None) # Ensure offer_id is provided @@ -611,23 +610,31 @@ async def _on_lookup_invoice( # Ensure payment_hash or invoice are provided if not payment_hash and not invoice: raise Exception("Missing payment_hash or invoice") + funding_source = get_funding_source() + # Extract hash from invoice if not provided if not payment_hash: - invoice_data = bolt11_decode(invoice) + invoice_data = await funding_source.decode_invoice(invoice) + + if not invoice_data: + raise Exception("Invalid invoice") payment_hash = invoice_data.payment_hash # hardening # assert_valid_sha256(payment_hash) - assert_valid_bolt11(invoice) + assert_valid_bolt12(invoice) # ## # # Get payment data payment = await get_wallet_payment(nwc.wallet, payment_hash) if not payment: raise Exception("Payment not found") - invoice_data = bolt11_decode(payment.bolt11) + invoice_data = await funding_source.decode_invoice(invoice) + + if not invoice_data: + raise Exception("Invalid invoice") is_settled = not payment.pending - timestamp = int(payment.time.timestamp()) or int(invoice_data.date) + timestamp = int(payment.time.timestamp()) or int(invoice_data.invoice_created_at) expiry = int(payment.expiry.timestamp()) or timestamp + 3600 preimage = ( payment.preimage From 52bccc9f43927592c6c593039414c50feace6e2e Mon Sep 17 00:00:00 2001 From: 21M4TW <21m4tw@proton.me> Date: Mon, 9 Jun 2025 14:44:09 -0400 Subject: [PATCH 11/13] -Add bolt12 support to pay_invoice and multi_pay_invoice -This should complete the initial support for Bolt12. The only remaining issue is regarding the invoice string for Bolt12 payments. Currently there is no bolt12 column in the apipayments table. This can be added if this is deemed useful. --- tasks.py | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/tasks.py b/tasks.py index 9a9ae91..b55780b 100644 --- a/tasks.py +++ b/tasks.py @@ -152,11 +152,19 @@ async def _on_pay_invoice( # Ensures invoice is provided if not invoice: raise Exception("Missing invoice") - invoice_data = bolt11_decode(invoice) + # hardening # + # hardening # + assert_valid_bolt12(invoice) + # ## # + + funding_source = get_funding_source() + invoice_data = await funding_source.decode_invoice(invoice) + + if not invoice_data: + raise Exception("Invalid invoice " + invoice) amount_msats = int(invoice_data.amount_msat or 0) # hardening # - assert_valid_bolt11(invoice) assert_valid_msats(amount_msats) # ## # @@ -192,6 +200,8 @@ async def _on_multi_pay_invoice( invoices = params.get("invoices", []) results: List[Tuple[Optional[Dict], Optional[Dict], List]] = [] + funding_source = get_funding_source() + # Ensures all invoices are provided for i in invoices: invoice = i.get("invoice", None) @@ -202,11 +212,18 @@ async def _on_multi_pay_invoice( try: invoice_id = i.get("id", None) invoice = i.get("invoice", None) - invoice_data = bolt11_decode(invoice) + + # hardening # + assert_valid_bolt12(invoice) + # ## # + + invoice_data = await funding_source.decode_invoice(invoice) + + if not invoice_data: + raise Exception("Invalid invoice " + invoice) amount_msats = int(invoice_data.amount_msat or 0) # hardening # - assert_valid_bolt11(invoice) assert_valid_msats(amount_msats) if invoice_id: assert_sane_string(invoice_id) @@ -617,7 +634,7 @@ async def _on_lookup_invoice( invoice_data = await funding_source.decode_invoice(invoice) if not invoice_data: - raise Exception("Invalid invoice") + raise Exception("Invalid invoice " + invoice) payment_hash = invoice_data.payment_hash # hardening # @@ -632,7 +649,7 @@ async def _on_lookup_invoice( invoice_data = await funding_source.decode_invoice(invoice) if not invoice_data: - raise Exception("Invalid invoice") + raise Exception("Invalid invoice " + invoice) is_settled = not payment.pending timestamp = int(payment.time.timestamp()) or int(invoice_data.invoice_created_at) expiry = int(payment.expiry.timestamp()) or timestamp + 3600 From ba68d720b82de74ecaa168b238010ac8beb5333f Mon Sep 17 00:00:00 2001 From: 21M4TW <21m4tw@proton.me> Date: Mon, 9 Jun 2025 15:44:12 -0400 Subject: [PATCH 12/13] -Some minor fixes (removing some debug print statements and moving up hardening checks --- nwcp.py | 2 -- tasks.py | 5 ++++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/nwcp.py b/nwcp.py index b0b842d..4a5023a 100644 --- a/nwcp.py +++ b/nwcp.py @@ -219,7 +219,6 @@ async def _send(self, data: List[Any]): return await self._wait_for_connection() # ensure the connection is established tx = self._json_dumps(data) - logger.debug(tx) await self.ws.send(tx) def _get_new_subid(self) -> str: @@ -494,7 +493,6 @@ async def _connect_to_relay(self): ): # receive messages until the instance is shutting down try: reply = await ws.recv() - logger.debug(reply) if isinstance(reply, bytes): reply = reply.decode("utf-8") await self._on_message(ws, reply) diff --git a/tasks.py b/tasks.py index 3bee467..e591f81 100644 --- a/tasks.py +++ b/tasks.py @@ -628,6 +628,10 @@ async def _on_lookup_invoice( raise Exception("Missing payment_hash or invoice") funding_source = get_funding_source() + # hardening # + assert_valid_bolt12(invoice) + # ## # + # Extract hash from invoice if not provided if not payment_hash: invoice_data = await funding_source.decode_invoice(invoice) @@ -638,7 +642,6 @@ async def _on_lookup_invoice( # hardening # assert_valid_sha256(payment_hash) - assert_valid_bolt12(invoice) # ## # # Get payment data From f07194af38839637ffe859f573209b56e836eef0 Mon Sep 17 00:00:00 2001 From: 21M4TW <21m4tw@proton.me> Date: Tue, 10 Jun 2025 23:21:14 -0400 Subject: [PATCH 13/13] -Renaming offer's "memo" field as "description" --- tasks.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tasks.py b/tasks.py index e591f81..99fc595 100644 --- a/tasks.py +++ b/tasks.py @@ -251,7 +251,7 @@ async def _on_multi_pay_invoice( def _offer_to_dict(offer: Offer) -> Dict: res = { "offer": offer.bolt12, - "memo": offer.memo, + "description": offer.memo, "amount": offer.amount, "offer_id": offer.offer_id, "active": offer.active, @@ -283,15 +283,15 @@ async def _on_make_offer( raise Exception("Pubkey has no associated wallet") params = payload.get("params", {}) amount_msats = params.get("amount", None) - memo = params.get("memo", "") + description = params.get("description", "") absolute_expiry = params.get("absolute_expiry", None) single_use = params.get("single_use", False) # hardening # if amount_msats is not None: assert_valid_msats(amount_msats) - if memo: - assert_sane_string(memo) + if description: + assert_sane_string(description) if absolute_expiry: assert_valid_expiration_seconds(absolute_expiry) assert_boolean(single_use) @@ -300,7 +300,7 @@ async def _on_make_offer( offer = await create_offer( wallet_id=nwc.wallet, amount_sat=amount_msats * 0.001 if amount_msats is not None else None, - memo=memo, + memo=description, absolute_expiry=absolute_expiry, single_use=single_use, )