From 0a5beb75a219f30112ee510d613c70ffde653e06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Sun, 6 Aug 2023 18:35:34 +0200 Subject: [PATCH 1/9] [FEAT] Improve tests (#296) * test cli arent async tests * unused SERVER_ENDPOINT var * async test werent marked async * make test didnt use correct ports * enable more verbose test logging * refactor conftest variable * not needed anymore are set in conftest * using test_data now for conftest * formatting * comment out invalid hex * remove test dir before creating it to be sure * keep data from altest testrun and ad test_data to ignore * ignore error for CI * add duplicate env var * fix confest * Update pyproject.toml * fix up tests * short p2pk locktimes for faster tests --------- Co-authored-by: callebtc <93376500+callebtc@users.noreply.github.com> --- .env.example | 3 +- .gitignore | 1 + Makefile | 2 -- cashu/wallet/api/router.py | 50 ++++++++++++++++++---------------- tests/conftest.py | 56 ++++++++++++++++---------------------- tests/test_cli.py | 22 +++------------ tests/test_mint.py | 2 -- tests/test_wallet.py | 10 ++++--- tests/test_wallet_api.py | 8 +++--- tests/test_wallet_p2pk.py | 20 ++++++++------ tests/test_wallet_p2sh.py | 8 ++++-- 11 files changed, 85 insertions(+), 97 deletions(-) diff --git a/.env.example b/.env.example index 3e7ca311..daad78fd 100644 --- a/.env.example +++ b/.env.example @@ -17,7 +17,7 @@ TOR=TRUE # NOSTR # nostr private key to which to receive tokens to -NOSTR_PRIVATE_KEY=nostr_privatekey_here_hex_or_bech32_nsec +# NOSTR_PRIVATE_KEY=nostr_privatekey_here_hex_or_bech32_nsec # nostr relays (comma separated list) NOSTR_RELAYS=["wss://nostr-pub.wellorder.net"] @@ -38,7 +38,6 @@ MINT_INFO_CONTACT=[["email","contact@me.com"], ["twitter","@me"], ["nostr", "np MINT_INFO_MOTD="Message to users" MINT_PRIVATE_KEY=supersecretprivatekey -MINT_DATABASE=data/mint # increment derivation path to rotate to a new keyset MINT_DERIVATION_PATH="0/0/0/0" diff --git a/.gitignore b/.gitignore index c8945098..21e0d774 100644 --- a/.gitignore +++ b/.gitignore @@ -133,6 +133,7 @@ tor.pid # Default data directory /data +/test_data # MacOS .DS_Store diff --git a/Makefile b/Makefile index 613e020b..3e17cb21 100644 --- a/Makefile +++ b/Makefile @@ -32,8 +32,6 @@ package: python setup.py sdist bdist_wheel test: - LIGHTNING=false \ - TOR=false \ poetry run pytest tests --cov-report xml --cov cashu install: diff --git a/cashu/wallet/api/router.py b/cashu/wallet/api/router.py index 667dd1af..7ad7e9de 100644 --- a/cashu/wallet/api/router.py +++ b/cashu/wallet/api/router.py @@ -38,32 +38,35 @@ router: APIRouter = APIRouter() -def create_wallet( - url=settings.mint_url, dir=settings.cashu_dir, name=settings.wallet_name -): - return Wallet( - url=url, - db=os.path.join(dir, name), - name=name, +async def mint_wallet(mint_url: Optional[str] = None): + wallet: Wallet = await Wallet.with_db( + mint_url or settings.mint_url, + db=os.path.join(settings.cashu_dir, settings.wallet_name), + name=settings.wallet_name, ) - - -async def load_mint(wallet: Wallet, mint: Optional[str] = None): - if mint: - wallet = create_wallet(mint) - await init_wallet(wallet) await wallet.load_mint() return wallet -wallet = create_wallet() +wallet: Wallet = Wallet( + settings.mint_url, + db=os.path.join(settings.cashu_dir, settings.wallet_name), + name=settings.wallet_name, +) @router.on_event("startup") async def start_wallet(): + global wallet + wallet = await Wallet.with_db( + settings.mint_url, + db=os.path.join(settings.cashu_dir, settings.wallet_name), + name=settings.wallet_name, + ) + if settings.tor and not TorProxy().check_platform(): raise Exception("tor not working.") - await init_wallet(wallet) + await wallet.load_mint() @router.post("/pay", name="Pay lightning invoice", response_model=PayResponse) @@ -78,7 +81,7 @@ async def pay( raise Exception("lightning not enabled.") global wallet - wallet = await load_mint(wallet, mint) + wallet = await mint_wallet(mint) total_amount, fee_reserve_sat = await wallet.get_pay_amount_with_fees(invoice) assert total_amount > 0, "amount has to be larger than zero." @@ -116,7 +119,7 @@ async def invoice( print(f"Requesting split with {n_splits}*{split} sat tokens.") global wallet - wallet = await load_mint(wallet, mint) + wallet = await mint_wallet(mint) if not settings.lightning: await wallet.mint(amount, split=optional_split) return InvoiceResponse( @@ -150,8 +153,8 @@ async def swap( ): if not settings.lightning: raise Exception("lightning not supported") - incoming_wallet = await load_mint(wallet, mint=incoming_mint) - outgoing_wallet = await load_mint(wallet, mint=outgoing_mint) + incoming_wallet = await mint_wallet(incoming_mint) + outgoing_wallet = await mint_wallet(outgoing_mint) if incoming_wallet.url == outgoing_wallet.url: raise Exception("mints for swap have to be different") @@ -159,7 +162,7 @@ async def swap( invoice = await incoming_wallet.request_mint(amount) # pay invoice from outgoing mint - await outgoing_wallet.load_proofs() + await outgoing_wallet.load_proofs(reload=True) total_amount, fee_reserve_sat = await outgoing_wallet.get_pay_amount_with_fees( invoice.pr ) @@ -174,7 +177,7 @@ async def swap( # mint token in incoming mint await incoming_wallet.mint(amount, hash=invoice.hash) - await incoming_wallet.load_proofs() + await incoming_wallet.load_proofs(reload=True) mint_balances = await incoming_wallet.balance_per_minturl() return SwapResponse( outgoing_mint=outgoing_mint, @@ -191,7 +194,7 @@ async def swap( response_model=BalanceResponse, ) async def balance(): - await wallet.load_proofs() + await wallet.load_proofs(reload=True) keyset_balances = wallet.balance_per_keyset() mint_balances = await wallet.balance_per_minturl() return BalanceResponse( @@ -229,6 +232,7 @@ async def receive_command( nostr: bool = Query(default=False, description="Receive tokens via nostr"), all: bool = Query(default=False, description="Receive all pending tokens"), ): + wallet = await mint_wallet() initial_balance = wallet.available_balance if token: tokenObj: TokenV3 = deserialize_token_from_string(token) @@ -269,7 +273,7 @@ async def burn( ): global wallet if not delete: - wallet = await load_mint(wallet, mint) + wallet = await mint_wallet(mint) if not (all or token or force or delete) or (token and all): raise Exception( "enter a token or use --all to burn all pending tokens, --force to check all tokens" diff --git a/tests/conftest.py b/tests/conftest.py index a7d4c56b..1404216c 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -16,42 +16,36 @@ from cashu.mint import migrations as migrations_mint from cashu.mint.ledger import Ledger -SERVER_ENDPOINT = "http://localhost:3337" +SERVER_PORT = 3337 +SERVER_ENDPOINT = f"http://localhost:{SERVER_PORT}" + +settings.cashu_dir = "./test_data/" +settings.mint_host = "localhost" +settings.mint_port = SERVER_PORT +settings.mint_host = "0.0.0.0" +settings.mint_listen_port = SERVER_PORT +settings.mint_url = SERVER_ENDPOINT +settings.lightning = False +settings.tor = False +settings.mint_lightning_backend = "FakeWallet" +settings.mint_database = "./test_data/test_mint" +settings.mint_derivation_path = "0/0/0/0" +settings.mint_private_key = "TEST_PRIVATE_KEY" + +shutil.rmtree(settings.cashu_dir, ignore_errors=True) +Path(settings.cashu_dir).mkdir(parents=True, exist_ok=True) class UvicornServer(multiprocessing.Process): - def __init__(self, config: Config, private_key: str = "TEST_PRIVATE_KEY"): + def __init__(self, config: Config): super().__init__() self.server = Server(config=config) self.config = config - self.private_key = private_key def stop(self): self.terminate() def run(self, *args, **kwargs): - settings.lightning = False - settings.mint_lightning_backend = "FakeWallet" - settings.mint_database = "data/test_mint" - settings.mint_private_key = self.private_key - settings.mint_derivation_path = "0/0/0/0" - - dirpath = Path(settings.mint_database) - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - - dirpath = Path("data/wallet1") - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - - dirpath = Path("data/wallet2") - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - - dirpath = Path("data/wallet3") - if dirpath.exists() and dirpath.is_dir(): - shutil.rmtree(dirpath) - self.server.run() @@ -62,13 +56,13 @@ async def start_mint_init(ledger: Ledger): await ledger.load_used_proofs() await ledger.init_keysets() - db_file = "data/mint/test.sqlite3" + db_file = "test_data/mint/test.sqlite3" if os.path.exists(db_file): os.remove(db_file) ledger = Ledger( - db=Database("test", "data/mint"), - seed="TEST_PRIVATE_KEY", - derivation_path="0/0/0/0", + db=Database("test", "test_data/mint"), + seed=settings.mint_private_key, + derivation_path=settings.mint_derivation_path, lightning=FakeWallet(), ) await start_mint_init(ledger) @@ -77,12 +71,10 @@ async def start_mint_init(ledger: Ledger): @pytest.fixture(autouse=True, scope="session") def mint(): - settings.mint_listen_port = 3337 - settings.mint_url = "http://localhost:3337" config = uvicorn.Config( "cashu.mint.app:app", port=settings.mint_listen_port, - host="127.0.0.1", + host=settings.mint_listen_host, ) server = UvicornServer(config=config) diff --git a/tests/test_cli.py b/tests/test_cli.py index f84223fa..b2d2e659 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -16,14 +16,13 @@ def cli_prefix(): async def init_wallet(): wallet = await Wallet.with_db( url=settings.mint_host, - db="data/test_cli_wallet", + db="test_data/test_cli_wallet", name="wallet", ) await wallet.load_proofs() return wallet -@pytest.mark.asyncio def test_info(cli_prefix): runner = CliRunner() result = runner.invoke( @@ -37,7 +36,6 @@ def test_info(cli_prefix): assert result.exit_code == 0 -@pytest.mark.asyncio def test_info_with_mint(cli_prefix): runner = CliRunner() result = runner.invoke( @@ -51,7 +49,6 @@ def test_info_with_mint(cli_prefix): assert result.exit_code == 0 -@pytest.mark.asyncio def test_info_with_mnemonic(cli_prefix): runner = CliRunner() result = runner.invoke( @@ -65,7 +62,6 @@ def test_info_with_mnemonic(cli_prefix): assert result.exit_code == 0 -@pytest.mark.asyncio def test_balance(cli_prefix): runner = CliRunner() result = runner.invoke( @@ -80,7 +76,6 @@ def test_balance(cli_prefix): assert result.exit_code == 0 -@pytest.mark.asyncio def test_invoice(mint, cli_prefix): runner = CliRunner() result = runner.invoke( @@ -96,7 +91,6 @@ def test_invoice(mint, cli_prefix): assert result.exit_code == 0 -@pytest.mark.asyncio def test_invoice_with_split(mint, cli_prefix): runner = CliRunner() result = runner.invoke( @@ -108,7 +102,6 @@ def test_invoice_with_split(mint, cli_prefix): # assert wallet.proof_amounts.count(1) >= 10 -@pytest.mark.asyncio def test_wallets(cli_prefix): runner = CliRunner() result = runner.invoke( @@ -123,7 +116,6 @@ def test_wallets(cli_prefix): assert result.exit_code == 0 -@pytest.mark.asyncio def test_send(mint, cli_prefix): runner = CliRunner() result = runner.invoke( @@ -136,7 +128,6 @@ def test_send(mint, cli_prefix): assert "cashuA" in result.output, "output does not have a token" -@pytest.mark.asyncio def test_send_without_split(mint, cli_prefix): runner = CliRunner() result = runner.invoke( @@ -149,7 +140,6 @@ def test_send_without_split(mint, cli_prefix): assert "cashuA" in result.output, "output does not have a token" -@pytest.mark.asyncio def test_send_without_split_but_wrong_amount(mint, cli_prefix): runner = CliRunner() result = runner.invoke( @@ -159,7 +149,6 @@ def test_send_without_split_but_wrong_amount(mint, cli_prefix): assert "No proof with this amount found" in str(result.exception) -@pytest.mark.asyncio def test_receive_tokenv3(mint, cli_prefix): runner = CliRunner() token = ( @@ -181,10 +170,10 @@ def test_receive_tokenv3(mint, cli_prefix): print(result.output) -@pytest.mark.asyncio def test_receive_tokenv3_no_mint(mint, cli_prefix): - # this test works only if the previous test succeeds because we simulate the case where the mint URL is not in the token - # therefore, we need to know the mint keyset already and have the mint URL in the db + # this test works only if the previous test succeeds because we simulate the case + # where the mint URL is not in the token therefore, we need to know the mint keyset + # already and have the mint URL in the db runner = CliRunner() token = ( "cashuAeyJ0b2tlbiI6IFt7InByb29mcyI6IFt7ImlkIjogIjFjQ05JQVoyWC93MSIsICJhbW91bnQiOiAyLCAic2VjcmV0IjogIi1oM0ZXMFFoX1FYLW9ac1V2c0RuNlEiLC" @@ -205,7 +194,6 @@ def test_receive_tokenv3_no_mint(mint, cli_prefix): print(result.output) -@pytest.mark.asyncio def test_receive_tokenv2(mint, cli_prefix): runner = CliRunner() token = ( @@ -223,7 +211,6 @@ def test_receive_tokenv2(mint, cli_prefix): print(result.output) -@pytest.mark.asyncio def test_receive_tokenv1(mint, cli_prefix): runner = CliRunner() token = ( @@ -240,7 +227,6 @@ def test_receive_tokenv1(mint, cli_prefix): print(result.output) -@pytest.mark.asyncio() def test_nostr_send(mint, cli_prefix): runner = CliRunner() result = runner.invoke( diff --git a/tests/test_mint.py b/tests/test_mint.py index 1be52a19..2a5e22db 100644 --- a/tests/test_mint.py +++ b/tests/test_mint.py @@ -8,8 +8,6 @@ from cashu.core.settings import settings from cashu.mint.ledger import Ledger -SERVER_ENDPOINT = "http://localhost:3338" - async def assert_err(f, msg): """Compute f() and expect an error message 'msg'.""" diff --git a/tests/test_wallet.py b/tests/test_wallet.py index fdcf6647..dc2d8507 100644 --- a/tests/test_wallet.py +++ b/tests/test_wallet.py @@ -50,7 +50,7 @@ async def reset_wallet_db(wallet: Wallet): async def wallet1(mint): wallet1 = await Wallet1.with_db( url=SERVER_ENDPOINT, - db="data/wallet1", + db="test_data/wallet1", name="wallet1", ) await wallet1.load_mint() @@ -62,7 +62,7 @@ async def wallet1(mint): async def wallet2(mint): wallet2 = await Wallet2.with_db( url=SERVER_ENDPOINT, - db="data/wallet2", + db="test_data/wallet2", name="wallet2", ) await wallet2.load_mint() @@ -72,13 +72,13 @@ async def wallet2(mint): @pytest_asyncio.fixture(scope="function") async def wallet3(mint): - dirpath = Path("data/wallet3") + dirpath = Path("test_data/wallet3") if dirpath.exists() and dirpath.is_dir(): shutil.rmtree(dirpath) wallet3 = await Wallet1.with_db( url=SERVER_ENDPOINT, - db="data/wallet3", + db="test_data/wallet3", name="wallet3", ) await wallet3.db.execute("DELETE FROM proofs") @@ -313,6 +313,7 @@ async def test_p2sh_receive_with_wrong_wallet(wallet1: Wallet, wallet2: Wallet): await assert_err(wallet2.redeem(send_proofs), "lock not found.") # wrong receiver +@pytest.mark.asyncio async def test_token_state(wallet1: Wallet): await wallet1.mint(64) assert wallet1.balance == 64 @@ -321,6 +322,7 @@ async def test_token_state(wallet1: Wallet): assert resp.dict()["pending"] +@pytest.mark.asyncio async def test_bump_secret_derivation(wallet3: Wallet): await wallet3._init_private_key( "half depart obvious quality work element tank gorilla view sugar picture humble" diff --git a/tests/test_wallet_api.py b/tests/test_wallet_api.py index bda48686..799f834c 100644 --- a/tests/test_wallet_api.py +++ b/tests/test_wallet_api.py @@ -12,8 +12,8 @@ async def wallet(mint): wallet = await Wallet.with_db( url=SERVER_ENDPOINT, - db="data/test_wallet_api", - name="wallet_api", + db="test_data/wallet", + name="wallet", ) await wallet.load_mint() wallet.status() @@ -89,7 +89,7 @@ async def test_receive_all(wallet: Wallet): with TestClient(app) as client: response = client.post("/receive?all=true") assert response.status_code == 200 - assert response.json()["initial_balance"] + assert response.json()["initial_balance"] == 0 assert response.json()["balance"] @@ -100,7 +100,7 @@ async def test_burn_all(wallet: Wallet): assert response.status_code == 200 response = client.post("/burn?all=true") assert response.status_code == 200 - assert response.json()["balance"] + assert response.json()["balance"] == 0 @pytest.mark.asyncio diff --git a/tests/test_wallet_p2pk.py b/tests/test_wallet_p2pk.py index e92a8509..50101af9 100644 --- a/tests/test_wallet_p2pk.py +++ b/tests/test_wallet_p2pk.py @@ -34,7 +34,9 @@ def assert_amt(proofs: List[Proof], expected: int): @pytest_asyncio.fixture(scope="function") async def wallet1(mint): - wallet1 = await Wallet1.with_db(SERVER_ENDPOINT, "data/wallet_p2pk_1", "wallet1") + wallet1 = await Wallet1.with_db( + SERVER_ENDPOINT, "test_data/wallet_p2pk_1", "wallet1" + ) await migrate_databases(wallet1.db, migrations) await wallet1.load_mint() wallet1.status() @@ -43,7 +45,9 @@ async def wallet1(mint): @pytest_asyncio.fixture(scope="function") async def wallet2(mint): - wallet2 = await Wallet2.with_db(SERVER_ENDPOINT, "data/wallet_p2pk_2", "wallet2") + wallet2 = await Wallet2.with_db( + SERVER_ENDPOINT, "test_data/wallet_p2pk_2", "wallet2" + ) await migrate_databases(wallet2.db, migrations) wallet2.private_key = PrivateKey(secrets.token_bytes(32), raw=True) await wallet2.load_mint() @@ -95,7 +99,7 @@ async def test_p2pk_short_locktime_receive_with_wrong_private_key( pubkey_wallet2 = await wallet2.create_p2pk_pubkey() # receiver side # sender side secret_lock = await wallet1.create_p2pk_lock( - pubkey_wallet2, locktime_seconds=4 + pubkey_wallet2, locktime_seconds=2 ) # sender side _, send_proofs = await wallet1.split_to_send( wallet1.proofs, 8, secret_lock=secret_lock @@ -107,7 +111,7 @@ async def test_p2pk_short_locktime_receive_with_wrong_private_key( wallet2.redeem(send_proofs), "Mint Error: no valid signature provided for input.", ) - await asyncio.sleep(6) + await asyncio.sleep(2) # should succeed because even with the wrong private key we # can redeem the tokens after the locktime await wallet2.redeem(send_proofs_copy) @@ -122,7 +126,7 @@ async def test_p2pk_locktime_with_refund_pubkey(wallet1: Wallet, wallet2: Wallet assert garbage_pubkey secret_lock = await wallet1.create_p2pk_lock( garbage_pubkey.serialize().hex(), # create lock to unspendable pubkey - locktime_seconds=4, # locktime + locktime_seconds=2, # locktime tags=Tags([["refund", pubkey_wallet2]]), # refund pubkey ) # sender side _, send_proofs = await wallet1.split_to_send( @@ -134,7 +138,7 @@ async def test_p2pk_locktime_with_refund_pubkey(wallet1: Wallet, wallet2: Wallet wallet2.redeem(send_proofs), "Mint Error: no valid signature provided for input.", ) - await asyncio.sleep(6) + await asyncio.sleep(2) # we can now redeem because of the refund locktime await wallet2.redeem(send_proofs_copy) @@ -150,7 +154,7 @@ async def test_p2pk_locktime_with_wrong_refund_pubkey(wallet1: Wallet, wallet2: assert garbage_pubkey_2 secret_lock = await wallet1.create_p2pk_lock( garbage_pubkey.serialize().hex(), # create lock to unspendable pubkey - locktime_seconds=4, # locktime + locktime_seconds=2, # locktime tags=Tags([["refund", garbage_pubkey_2.serialize().hex()]]), # refund pubkey ) # sender side _, send_proofs = await wallet1.split_to_send( @@ -162,7 +166,7 @@ async def test_p2pk_locktime_with_wrong_refund_pubkey(wallet1: Wallet, wallet2: wallet2.redeem(send_proofs), "Mint Error: no valid signature provided for input.", ) - await asyncio.sleep(6) + await asyncio.sleep(2) # we still can't redeem it because we used garbage_pubkey_2 as a refund pubkey await assert_err( wallet2.redeem(send_proofs_copy), diff --git a/tests/test_wallet_p2sh.py b/tests/test_wallet_p2sh.py index ebfe2a11..95402047 100644 --- a/tests/test_wallet_p2sh.py +++ b/tests/test_wallet_p2sh.py @@ -33,7 +33,9 @@ def assert_amt(proofs: List[Proof], expected: int): @pytest_asyncio.fixture(scope="function") async def wallet1(mint): - wallet1 = await Wallet1.with_db(SERVER_ENDPOINT, "data/wallet_p2sh_1", "wallet1") + wallet1 = await Wallet1.with_db( + SERVER_ENDPOINT, "test_data/wallet_p2sh_1", "wallet1" + ) await migrate_databases(wallet1.db, migrations) await wallet1.load_mint() wallet1.status() @@ -42,7 +44,9 @@ async def wallet1(mint): @pytest_asyncio.fixture(scope="function") async def wallet2(mint): - wallet2 = await Wallet2.with_db(SERVER_ENDPOINT, "data/wallet_p2sh_2", "wallet2") + wallet2 = await Wallet2.with_db( + SERVER_ENDPOINT, "test_data/wallet_p2sh_2", "wallet2" + ) await migrate_databases(wallet2.db, migrations) wallet2.private_key = PrivateKey(secrets.token_bytes(32), raw=True) await wallet2.load_mint() From 88393fa4c4e667116e7c5a0e63784536f8a62040 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Thu, 24 Aug 2023 09:47:47 +0200 Subject: [PATCH 2/9] [DEV] add ruff and remove isort and flake (#300) * [DEV] add ruff and remove isort and flake - precommit - workflow - Makefile updated black * configure black to use default line-length * reformat to 88 chars line-length * fix ugly comments --- .flake8 | 8 -- .github/workflows/checks.yml | 11 +-- .pre-commit-config.yaml | 16 ++-- Makefile | 15 ++-- cashu/core/base.py | 36 ++++----- cashu/core/bolt11.py | 1 - cashu/core/db.py | 6 +- cashu/core/migrations.py | 6 +- cashu/core/script.py | 6 +- cashu/mint/app.py | 11 ++- cashu/mint/crud.py | 12 +-- cashu/mint/ledger.py | 58 ++++++++------ cashu/mint/migrations.py | 60 +++++--------- cashu/mint/router.py | 38 ++++++--- cashu/mint/startup.py | 3 +- cashu/wallet/api/router.py | 5 +- cashu/wallet/cli/cli.py | 55 ++++++++----- cashu/wallet/cli/cli_helpers.py | 3 +- cashu/wallet/crud.py | 12 +-- cashu/wallet/helpers.py | 3 +- cashu/wallet/migrations.py | 60 +++++--------- cashu/wallet/nostr.py | 5 +- cashu/wallet/wallet.py | 9 ++- poetry.lock | 135 +++++++++++++------------------- pyproject.toml | 64 ++++++++++++++- tests/test_wallet.py | 52 +++++------- 26 files changed, 357 insertions(+), 333 deletions(-) delete mode 100644 .flake8 diff --git a/.flake8 b/.flake8 deleted file mode 100644 index c64e6e91..00000000 --- a/.flake8 +++ /dev/null @@ -1,8 +0,0 @@ -[flake8] -max-line-length = 150 -exclude = cashu/nostr, cashu/core/bolt11.py -ignore = - # E203 whitespace before ':' black does not like it - E203, - # W503: line break before binary operator - W503, diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 8ba2d5c4..e001f35e 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -24,9 +24,7 @@ jobs: run: poetry install - name: Check black run: make black-check - - name: Check isort - run: make isort-check - linting: + mypy: runs-on: ubuntu-latest strategy: matrix: @@ -49,5 +47,8 @@ jobs: run: yes | poetry run mypy cashu --install-types || true - name: Run mypy run: poetry run mypy cashu --ignore-missing - - name: Run flake8 - run: poetry run flake8 + ruff: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: chartboost/ruff-action@v1 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 8bba7a27..22f30900 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,5 +1,4 @@ exclude: '^cashu/nostr/.*' - repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.3.0 @@ -14,16 +13,11 @@ repos: - id: mixed-line-ending - id: check-case-conflict - repo: https://github.com/psf/black - rev: 22.6.0 + rev: 23.7.0 hooks: - id: black - - repo: https://github.com/pycqa/isort - rev: 5.12.0 + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.0.283 hooks: - - id: isort - args: ['--profile', 'black'] - - repo: https://github.com/pycqa/flake8 - rev: 6.0.0 - hooks: - - id: flake8 - entry: poetry run flake8 + - id: ruff + args: [ --fix, --exit-non-zero-on-fix ] diff --git a/Makefile b/Makefile index 3e17cb21..fb3cbfa8 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,8 @@ -isort: - poetry run isort --profile black . --skip cashu/nostr +ruff: + poetry run ruff check . --fix -isort-check: - poetry run isort --profile black --check-only . --skip cashu/nostr +ruff-check: + poetry run ruff check . black: poetry run black . --exclude cashu/nostr @@ -13,12 +13,9 @@ black-check: mypy: poetry run mypy cashu --ignore-missing -flake8: - poetry run flake8 cashu +format: black ruff -format: isort black - -check: isort-check black-check flake8 mypy +check: black-check ruff-check mypy clean: rm -r cashu.egg-info/ || true diff --git a/cashu/core/base.py b/cashu/core/base.py index 3860e622..525b4b65 100644 --- a/cashu/core/base.py +++ b/cashu/core/base.py @@ -22,8 +22,8 @@ class SecretKind: class SigFlags: - SIG_INPUTS = ( - "SIG_INPUTS" # require signatures only on the inputs (default signature flag) + SIG_INPUTS = ( # require signatures only on the inputs (default signature flag) + "SIG_INPUTS" ) SIG_ALL = "SIG_ALL" # require signatures on inputs and outputs @@ -159,20 +159,17 @@ class Proof(BaseModel): Value token """ - id: Union[ - None, str - ] = "" # NOTE: None for backwards compatibility for old clients that do not include the keyset id < 0.3 + # NOTE: None for backwards compatibility for old clients that do not include the keyset id < 0.3 + id: Union[None, str] = "" amount: int = 0 secret: str = "" # secret or message to be blinded and signed C: str = "" # signature on secret, unblinded by wallet p2pksigs: Union[List[str], None] = [] # P2PK signature p2shscript: Union[P2SHScript, None] = None # P2SH spending condition - reserved: Union[ - None, bool - ] = False # whether this proof is reserved for sending, used for coin management in the wallet - send_id: Union[ - None, str - ] = "" # unique ID of send attempt, used for grouping pending tokens in the wallet + # whether this proof is reserved for sending, used for coin management in the wallet + reserved: Union[None, bool] = False + # unique ID of send attempt, used for grouping pending tokens in the wallet + send_id: Union[None, str] = "" time_created: Union[None, str] = "" time_reserved: Union[None, str] = "" derivation_path: Union[None, str] = "" # derivation path of the proof @@ -338,9 +335,9 @@ class CheckSpendableRequest(BaseModel): class CheckSpendableResponse(BaseModel): spendable: List[bool] - pending: Optional[ - List[bool] - ] = None # TODO: Uncomment when all mints are updated to 0.12.3 and support /check + pending: Optional[List[bool]] = ( + None # TODO: Uncomment when all mints are updated to 0.12.3 and support /check + ) # with pending tokens (kept for backwards compatibility of new wallets with old mints) @@ -421,9 +418,11 @@ def deserialize(serialized: str): return cls( id=row["id"], - public_keys=deserialize(str(row["public_keys"])) - if dict(row).get("public_keys") - else {}, + public_keys=( + deserialize(str(row["public_keys"])) + if dict(row).get("public_keys") + else {} + ), mint_url=row["mint_url"], valid_from=row["valid_from"], valid_to=row["valid_to"], @@ -489,7 +488,8 @@ def generate_keys(self, seed): self.id = derive_keyset_id(self.public_keys) # type: ignore if backwards_compatibility_pre_0_12: logger.warning( - f"WARNING: Using weak key derivation for keyset {self.id} (backwards compatibility < 0.12)" + f"WARNING: Using weak key derivation for keyset {self.id} (backwards" + " compatibility < 0.12)" ) diff --git a/cashu/core/bolt11.py b/cashu/core/bolt11.py index 962581d7..3c59fbb5 100644 --- a/cashu/core/bolt11.py +++ b/cashu/core/bolt11.py @@ -184,7 +184,6 @@ def lnencode(addr, privkey): tags_set = set() for k, v in addr.tags: - # BOLT #11: # # A writer MUST NOT include more than one `d`, `h`, `n` or `x` fields, diff --git a/cashu/core/db.py b/cashu/core/db.py index 0af326a2..60873862 100644 --- a/cashu/core/db.py +++ b/cashu/core/db.py @@ -117,9 +117,9 @@ def _parse_timestamp(value, _): psycopg2.extensions.new_type( # type: ignore (1082, 1083, 1266), "DATE2INT", - lambda value, curs: time.mktime(value.timetuple()) - if value is not None - else None, + lambda value, curs: ( + time.mktime(value.timetuple()) if value is not None else None + ), ) ) diff --git a/cashu/core/migrations.py b/cashu/core/migrations.py index 37a697c3..ce3e2bfe 100644 --- a/cashu/core/migrations.py +++ b/cashu/core/migrations.py @@ -37,11 +37,13 @@ async def run_migration(db, migrations_module): exists = None if conn.type == SQLITE: exists = await conn.fetchone( - f"SELECT * FROM sqlite_master WHERE type='table' AND name='{table_with_schema(db, 'dbversions')}'" + "SELECT * FROM sqlite_master WHERE type='table' AND" + f" name='{table_with_schema(db, 'dbversions')}'" ) elif conn.type in {POSTGRES, COCKROACH}: exists = await conn.fetchone( - f"SELECT * FROM information_schema.tables WHERE table_name = '{table_with_schema(db, 'dbversions')}'" + "SELECT * FROM information_schema.tables WHERE table_name =" + f" '{table_with_schema(db, 'dbversions')}'" ) if not exists: diff --git a/cashu/core/script.py b/cashu/core/script.py index ff471d14..0fc2a8ea 100644 --- a/cashu/core/script.py +++ b/cashu/core/script.py @@ -134,7 +134,8 @@ def verify_bitcoin_script(txin_redeemScript_b64, txin_signature_b64): txin_redeemScript_b64 = base64.urlsafe_b64encode(txin_redeemScript).decode() txin_signature_b64 = base64.urlsafe_b64encode(txin_signature).decode() print( - f"Carol to Bob:\nscript: {txin_redeemScript.__repr__()}\nscript: {txin_redeemScript_b64}\nsignature: {txin_signature_b64}\n" + f"Carol to Bob:\nscript: {txin_redeemScript.__repr__()}\nscript:" + f" {txin_redeemScript_b64}\nsignature: {txin_signature_b64}\n" ) print("") # --------- @@ -155,7 +156,8 @@ def verify_bitcoin_script(txin_redeemScript_b64, txin_signature_b64): tx, _ = step1_bob_carol_create_tx(txin_p2sh_address) print( - f"Bob verifies:\nscript: {txin_redeemScript_b64}\nsignature: {txin_signature_b64}\n" + f"Bob verifies:\nscript: {txin_redeemScript_b64}\nsignature:" + f" {txin_signature_b64}\n" ) script_valid = step3_bob_verify_script(txin_signature, txin_redeemScript, tx) # MINT redeems tokens and stores P2SH:txin_p2sh_address diff --git a/cashu/mint/app.py b/cashu/mint/app.py index 3b4ef326..412cd907 100644 --- a/cashu/mint/app.py +++ b/cashu/mint/app.py @@ -36,11 +36,16 @@ def configure_logger() -> None: class Formatter: def __init__(self): self.padding = 0 - self.minimal_fmt: str = "{time:YYYY-MM-DD HH:mm:ss.SS} | {level} | {message}\n" + self.minimal_fmt: str = ( + "{time:YYYY-MM-DD HH:mm:ss.SS} |" + " {level} | {message}\n" + ) if settings.debug: self.fmt: str = ( - "{time:YYYY-MM-DD HH:mm:ss.SS} | {level: <4} | {name}:" - "{function}:{line} | {message}\n" + "{time:YYYY-MM-DD HH:mm:ss.SS} | {level:" + " <4} |" + " {name}:{function}:{line}" + " | {message}\n" ) else: self.fmt: str = self.minimal_fmt diff --git a/cashu/mint/crud.py b/cashu/mint/crud.py index c7eaffcc..d15ab222 100644 --- a/cashu/mint/crud.py +++ b/cashu/mint/crud.py @@ -90,11 +90,9 @@ async def get_proofs_used( db: Database, conn: Optional[Connection] = None, ): - rows = await (conn or db).fetchall( - f""" + rows = await (conn or db).fetchall(f""" SELECT secret from {table_with_schema(db, 'proofs_used')} - """ - ) + """) return [row[0] for row in rows] @@ -123,11 +121,9 @@ async def get_proofs_pending( db: Database, conn: Optional[Connection] = None, ): - rows = await (conn or db).fetchall( - f""" + rows = await (conn or db).fetchall(f""" SELECT * from {table_with_schema(db, 'proofs_pending')} - """ - ) + """) return [Proof(**r) for r in rows] diff --git a/cashu/mint/ledger.py b/cashu/mint/ledger.py index 1544c110..8f972d58 100644 --- a/cashu/mint/ledger.py +++ b/cashu/mint/ledger.py @@ -276,9 +276,10 @@ def _verify_input_spending_conditions(self, proof: Proof) -> bool: if not valid: raise TransactionError("script invalid.") # check if secret commits to script address - assert secret.data == str( - txin_p2sh_address - ), f"secret does not contain correct P2SH address: {secret.data} is not {txin_p2sh_address}." + assert secret.data == str(txin_p2sh_address), ( + f"secret does not contain correct P2SH address: {secret.data} is not" + f" {txin_p2sh_address}." + ) return True # P2PK @@ -310,9 +311,10 @@ def _verify_input_spending_conditions(self, proof: Proof) -> bool: assert n_sigs_required > 0, "n_sigs must be positive." # check if enough signatures are present - assert ( - len(proof.p2pksigs) >= n_sigs_required - ), f"not enough signatures provided: {len(proof.p2pksigs)} < {n_sigs_required}." + assert len(proof.p2pksigs) >= n_sigs_required, ( + f"not enough signatures provided: {len(proof.p2pksigs)} <" + f" {n_sigs_required}." + ) n_valid_sigs_per_output = 0 # loop over all signatures in output @@ -327,20 +329,24 @@ def _verify_input_spending_conditions(self, proof: Proof) -> bool: ): n_valid_sigs_per_output += 1 logger.trace( - f"p2pk signature on input is valid: {input_sig} on {pubkey}." + f"p2pk signature on input is valid: {input_sig} on" + f" {pubkey}." ) continue else: logger.trace( - f"p2pk signature on input is invalid: {input_sig} on {pubkey}." + f"p2pk signature on input is invalid: {input_sig} on" + f" {pubkey}." ) # check if we have enough valid signatures assert n_valid_sigs_per_output, "no valid signature provided for input." - assert ( - n_valid_sigs_per_output >= n_sigs_required - ), f"signature threshold not met. {n_valid_sigs_per_output} < {n_sigs_required}." + assert n_valid_sigs_per_output >= n_sigs_required, ( + f"signature threshold not met. {n_valid_sigs_per_output} <" + f" {n_sigs_required}." + ) logger.trace( - f"{n_valid_sigs_per_output} of {n_sigs_required} valid signatures found." + f"{n_valid_sigs_per_output} of {n_sigs_required} valid signatures" + " found." ) logger.trace(proof.p2pksigs) @@ -424,11 +430,13 @@ def _verify_output_spending_conditions( ): n_valid_sigs_per_output += 1 assert n_valid_sigs_per_output, "no valid signature provided for output." - assert ( - n_valid_sigs_per_output >= n_sigs_required - ), f"signature threshold not met. {n_valid_sigs_per_output} < {n_sigs_required}." + assert n_valid_sigs_per_output >= n_sigs_required, ( + f"signature threshold not met. {n_valid_sigs_per_output} <" + f" {n_sigs_required}." + ) logger.trace( - f"{n_valid_sigs_per_output} of {n_sigs_required} valid signatures found." + f"{n_valid_sigs_per_output} of {n_sigs_required} valid signatures" + " found." ) logger.trace(output.p2pksigs) logger.trace("p2pk signatures on output is valid.") @@ -492,7 +500,8 @@ async def _request_lightning_invoice(self, amount: int): Tuple[str, str]: Bolt11 invoice and payment hash (for lookup) """ logger.trace( - f"_request_lightning_invoice: Requesting Lightning invoice for {amount} satoshis." + "_request_lightning_invoice: Requesting Lightning invoice for" + f" {amount} satoshis." ) error, balance = await self.lightning.status() logger.trace(f"_request_lightning_invoice: Lightning wallet balance: {balance}") @@ -549,14 +558,16 @@ async def _check_lightning_invoice( try: if amount > invoice.amount: raise LightningError( - f"requested amount too high: {amount}. Invoice amount: {invoice.amount}" + f"requested amount too high: {amount}. Invoice amount:" + f" {invoice.amount}" ) logger.trace( f"_check_lightning_invoice: checking invoice {invoice.payment_hash}" ) status = await self.lightning.get_invoice_status(invoice.payment_hash) logger.trace( - f"_check_lightning_invoice: invoice {invoice.payment_hash} status: {status}" + f"_check_lightning_invoice: invoice {invoice.payment_hash} status:" + f" {status}" ) if status.paid: return status.paid @@ -658,7 +669,8 @@ async def _unset_proofs_pending( try: for p in proofs: logger.trace( - f"crud: _unset_proofs_pending unsetting proof {p.secret} as pending" + f"crud: _unset_proofs_pending unsetting proof {p.secret} as" + " pending" ) await self.crud.unset_proof_pending(proof=p, db=self.db, conn=conn) logger.trace( @@ -1005,7 +1017,8 @@ async def check_fees(self, pr: str): decoded_invoice = bolt11.decode(pr) amount = math.ceil(decoded_invoice.amount_msat / 1000) logger.trace( - f"check_fees: checking lightning invoice: {decoded_invoice.payment_hash}" + "check_fees: checking lightning invoice:" + f" {decoded_invoice.payment_hash}" ) paid = await self.lightning.get_invoice_status(decoded_invoice.payment_hash) logger.trace(f"check_fees: paid: {paid}") @@ -1071,7 +1084,8 @@ async def split( # BEGIN backwards compatibility < 0.13.0 if amount is not None: logger.debug( - "Split: Client provided `amount` - backwards compatibility response pre 0.13.0" + "Split: Client provided `amount` - backwards compatibility response pre" + " 0.13.0" ) # split outputs according to amount total = sum_proofs(proofs) diff --git a/cashu/mint/migrations.py b/cashu/mint/migrations.py index 0ad57cdc..44779e62 100644 --- a/cashu/mint/migrations.py +++ b/cashu/mint/migrations.py @@ -2,19 +2,16 @@ async def m000_create_migrations_table(db: Database): - await db.execute( - f""" + await db.execute(f""" CREATE TABLE IF NOT EXISTS {table_with_schema(db, 'dbversions')} ( db TEXT PRIMARY KEY, version INT NOT NULL ) - """ - ) + """) async def m001_initial(db: Database): - await db.execute( - f""" + await db.execute(f""" CREATE TABLE IF NOT EXISTS {table_with_schema(db, 'promises')} ( amount {db.big_int} NOT NULL, B_b TEXT NOT NULL, @@ -23,11 +20,9 @@ async def m001_initial(db: Database): UNIQUE (B_b) ); - """ - ) + """) - await db.execute( - f""" + await db.execute(f""" CREATE TABLE IF NOT EXISTS {table_with_schema(db, 'proofs_used')} ( amount {db.big_int} NOT NULL, C TEXT NOT NULL, @@ -36,11 +31,9 @@ async def m001_initial(db: Database): UNIQUE (secret) ); - """ - ) + """) - await db.execute( - f""" + await db.execute(f""" CREATE TABLE IF NOT EXISTS {table_with_schema(db, 'invoices')} ( amount {db.big_int} NOT NULL, pr TEXT NOT NULL, @@ -50,49 +43,41 @@ async def m001_initial(db: Database): UNIQUE (hash) ); - """ - ) + """) - await db.execute( - f""" + await db.execute(f""" CREATE VIEW {table_with_schema(db, 'balance_issued')} AS SELECT COALESCE(SUM(s), 0) AS balance FROM ( SELECT SUM(amount) FROM {table_with_schema(db, 'promises')} WHERE amount > 0 ) AS s; - """ - ) + """) - await db.execute( - f""" + await db.execute(f""" CREATE VIEW {table_with_schema(db, 'balance_redeemed')} AS SELECT COALESCE(SUM(s), 0) AS balance FROM ( SELECT SUM(amount) FROM {table_with_schema(db, 'proofs_used')} WHERE amount > 0 ) AS s; - """ - ) + """) - await db.execute( - f""" + await db.execute(f""" CREATE VIEW {table_with_schema(db, 'balance')} AS SELECT s_issued - s_used FROM ( SELECT bi.balance AS s_issued, bu.balance AS s_used FROM {table_with_schema(db, 'balance_issued')} bi CROSS JOIN {table_with_schema(db, 'balance_redeemed')} bu ) AS balance; - """ - ) + """) async def m003_mint_keysets(db: Database): """ Stores mint keysets from different mints and epochs. """ - await db.execute( - f""" + await db.execute(f""" CREATE TABLE IF NOT EXISTS {table_with_schema(db, 'keysets')} ( id TEXT NOT NULL, derivation_path TEXT, @@ -104,10 +89,8 @@ async def m003_mint_keysets(db: Database): UNIQUE (derivation_path) ); - """ - ) - await db.execute( - f""" + """) + await db.execute(f""" CREATE TABLE IF NOT EXISTS {table_with_schema(db, 'mint_pubkeys')} ( id TEXT NOT NULL, amount INTEGER NOT NULL, @@ -116,8 +99,7 @@ async def m003_mint_keysets(db: Database): UNIQUE (id, pubkey) ); - """ - ) + """) async def m004_keysets_add_version(db: Database): @@ -133,8 +115,7 @@ async def m005_pending_proofs_table(db: Database) -> None: """ Store pending proofs. """ - await db.execute( - f""" + await db.execute(f""" CREATE TABLE IF NOT EXISTS {table_with_schema(db, 'proofs_pending')} ( amount INTEGER NOT NULL, C TEXT NOT NULL, @@ -143,8 +124,7 @@ async def m005_pending_proofs_table(db: Database) -> None: UNIQUE (secret) ); - """ - ) + """) async def m006_invoices_add_payment_hash(db: Database): diff --git a/cashu/mint/router.py b/cashu/mint/router.py index 2fbb8336..3ede2c6b 100644 --- a/cashu/mint/router.py +++ b/cashu/mint/router.py @@ -59,7 +59,10 @@ async def info() -> GetInfoResponse: "/keys", name="Mint public keys", summary="Get the public keys of the newest mint keyset", - response_description="A dictionary of all supported token values of the mint and their associated public key of the current keyset.", + response_description=( + "A dictionary of all supported token values of the mint and their associated" + " public key of the current keyset." + ), response_model=KeysResponse, ) async def keys(): @@ -74,7 +77,10 @@ async def keys(): "/keys/{idBase64Urlsafe}", name="Keyset public keys", summary="Public keys of a specific keyset", - response_description="A dictionary of all supported token values of the mint and their associated public key for a specific keyset.", + response_description=( + "A dictionary of all supported token values of the mint and their associated" + " public key for a specific keyset." + ), response_model=KeysResponse, ) async def keyset_keys(idBase64Urlsafe: str): @@ -109,7 +115,10 @@ async def keysets() -> KeysetsResponse: name="Request mint", summary="Request minting of new tokens", response_model=GetMintResponse, - response_description="A Lightning invoice to be paid and a hash to request minting of new tokens after payment.", + response_description=( + "A Lightning invoice to be paid and a hash to request minting of new tokens" + " after payment." + ), ) async def request_mint(amount: int = 0) -> GetMintResponse: """ @@ -135,7 +144,9 @@ async def request_mint(amount: int = 0) -> GetMintResponse: name="Mint tokens", summary="Mint tokens in exchange for a Bitcoin paymemt that the user has made", response_model=PostMintResponse, - response_description="A list of blinded signatures that can be used to create proofs.", + response_description=( + "A list of blinded signatures that can be used to create proofs." + ), ) async def mint( payload: PostMintRequest, @@ -163,9 +174,15 @@ async def mint( @router.post( "/melt", name="Melt tokens", - summary="Melt tokens for a Bitcoin payment that the mint will make for the user in exchange", + summary=( + "Melt tokens for a Bitcoin payment that the mint will make for the user in" + " exchange" + ), response_model=GetMeltResponse, - response_description="The state of the payment, a preimage as proof of payment, and a list of promises for change.", + response_description=( + "The state of the payment, a preimage as proof of payment, and a list of" + " promises for change." + ), ) async def melt(payload: PostMeltRequest) -> GetMeltResponse: """ @@ -225,7 +242,9 @@ async def check_fees(payload: CheckFeesRequest) -> CheckFeesResponse: name="Split", summary="Split proofs at a specified amount", response_model=Union[PostSplitResponse, PostSplitResponse_Deprecated], - response_description="A list of blinded signatures that can be used to create proofs.", + response_description=( + "A list of blinded signatures that can be used to create proofs." + ), ) async def split( payload: PostSplitRequest, @@ -259,8 +278,9 @@ async def split( else: frst_promises.insert(0, promise) # and insert at the beginning logger.trace( - f"Split into keep: {len(frst_promises)}: {sum([p.amount for p in frst_promises])} " - f"sat and send: {len(scnd_promises)}: {sum([p.amount for p in scnd_promises])} sat" + f"Split into keep: {len(frst_promises)}:" + f" {sum([p.amount for p in frst_promises])} sat and send:" + f" {len(scnd_promises)}: {sum([p.amount for p in scnd_promises])} sat" ) return PostSplitResponse_Deprecated(fst=frst_promises, snd=scnd_promises) # END backwards compatibility < 0.13 diff --git a/cashu/mint/startup.py b/cashu/mint/startup.py index f4c8de70..735f59e9 100644 --- a/cashu/mint/startup.py +++ b/cashu/mint/startup.py @@ -53,7 +53,8 @@ async def start_mint_init(): error_message, balance = await ledger.lightning.status() if error_message: logger.warning( - f"The backend for {ledger.lightning.__class__.__name__} isn't working properly: '{error_message}'", + f"The backend for {ledger.lightning.__class__.__name__} isn't working" + f" properly: '{error_message}'", RuntimeWarning, ) logger.info(f"Lightning balance: {balance} msat") diff --git a/cashu/wallet/api/router.py b/cashu/wallet/api/router.py index 7ad7e9de..3a671b6d 100644 --- a/cashu/wallet/api/router.py +++ b/cashu/wallet/api/router.py @@ -276,8 +276,9 @@ async def burn( wallet = await mint_wallet(mint) if not (all or token or force or delete) or (token and all): raise Exception( - "enter a token or use --all to burn all pending tokens, --force to check all tokens" - "or --delete with send ID to force-delete pending token from list if mint is unavailable.", + "enter a token or use --all to burn all pending tokens, --force to check" + " all tokensor --delete with send ID to force-delete pending token from" + " list if mint is unavailable.", ) if all: # check only those who are flagged as reserved diff --git a/cashu/wallet/cli/cli.py b/cashu/wallet/cli/cli.py index c3e6b377..9acf2b29 100644 --- a/cashu/wallet/cli/cli.py +++ b/cashu/wallet/cli/cli.py @@ -90,18 +90,27 @@ def wrapper(*args, **kwargs): async def cli(ctx: Context, host: str, walletname: str, tests: bool): if settings.tor and not TorProxy().check_platform(): error_str = ( - "Your settings say TOR=true but the built-in Tor bundle is not supported on your system. You have two options: Either install" - " Tor manually and set TOR=FALSE and SOCKS_HOST=localhost and SOCKS_PORT=9050 in your Cashu config (recommended). Or turn off Tor by " - "setting TOR=false (not recommended). Cashu will not work until you edit your config file accordingly." + "Your settings say TOR=true but the built-in Tor bundle is not supported on" + " your system. You have two options: Either install Tor manually and set" + " TOR=FALSE and SOCKS_HOST=localhost and SOCKS_PORT=9050 in your Cashu" + " config (recommended). Or turn off Tor by setting TOR=false (not" + " recommended). Cashu will not work until you edit your config file" + " accordingly." ) error_str += "\n\n" if settings.env_file: error_str += f"Edit your Cashu config file here: {settings.env_file}" env_path = settings.env_file else: - error_str += f"Ceate a new Cashu config file here: {os.path.join(settings.cashu_dir, '.env')}" + error_str += ( + "Ceate a new Cashu config file here:" + f" {os.path.join(settings.cashu_dir, '.env')}" + ) env_path = os.path.join(settings.cashu_dir, ".env") - error_str += f'\n\nYou can turn off Tor with this command: echo "TOR=FALSE" >> {env_path}' + error_str += ( + '\n\nYou can turn off Tor with this command: echo "TOR=FALSE" >>' + f" {env_path}" + ) raise Exception(error_str) ctx.ensure_object(dict) @@ -155,7 +164,8 @@ async def pay(ctx: Context, invoice: str, yes: bool): total_amount, fee_reserve_sat = await wallet.get_pay_amount_with_fees(invoice) if not yes: click.confirm( - f"Pay {total_amount - fee_reserve_sat} sat ({total_amount} sat with potential fees)?", + f"Pay {total_amount - fee_reserve_sat} sat ({total_amount} sat with" + " potential fees)?", abort=True, default=True, ) @@ -206,7 +216,8 @@ async def invoice(ctx: Context, amount: int, hash: str, split: int): print(f"Invoice: {invoice.pr}") print("") print( - f"If you abort this you can use this command to recheck the invoice:\ncashu invoice {amount} --hash {invoice.hash}" + "If you abort this you can use this command to recheck the" + f" invoice:\ncashu invoice {amount} --hash {invoice.hash}" ) check_until = time.time() + 5 * 60 # check for five minutes print("") @@ -232,7 +243,8 @@ async def invoice(ctx: Context, amount: int, hash: str, split: int): if not paid: print("\n") print( - "Invoice is not paid yet, stopping check. Use the command above to recheck after the invoice has been paid." + "Invoice is not paid yet, stopping check. Use the command above to" + " recheck after the invoice has been paid." ) # user paid invoice and want to check it @@ -306,7 +318,8 @@ async def balance(ctx: Context, verbose): print("") for k, v in keyset_balances.items(): print( - f"Keyset: {k} - Balance: {v['available']} sat (pending: {v['balance']-v['available']} sat)" + f"Keyset: {k} - Balance: {v['available']} sat (pending:" + f" {v['balance']-v['available']} sat)" ) print("") @@ -314,8 +327,9 @@ async def balance(ctx: Context, verbose): if verbose: print( - f"Balance: {wallet.available_balance} sat (pending: {wallet.balance-wallet.available_balance} sat) " - f"in {len([p for p in wallet.proofs if not p.reserved])} tokens" + f"Balance: {wallet.available_balance} sat (pending:" + f" {wallet.balance-wallet.available_balance} sat) in" + f" {len([p for p in wallet.proofs if not p.reserved])} tokens" ) else: print(f"Balance: {wallet.available_balance} sat") @@ -386,7 +400,7 @@ async def send_command( "-n", default=False, is_flag=True, - help="Receive tokens via nostr." "receive", + help="Receive tokens via nostr.receive", ) @click.option( "--all", "-a", default=False, is_flag=True, help="Receive all pending tokens." @@ -454,8 +468,9 @@ async def burn(ctx: Context, token: str, all: bool, force: bool, delete: str): await wallet.load_mint() if not (all or token or force or delete) or (token and all): print( - "Error: enter a token or use --all to burn all pending tokens, --force to check all tokens " - "or --delete with send ID to force-delete pending token from list if mint is unavailable." + "Error: enter a token or use --all to burn all pending tokens, --force to" + " check all tokens or --delete with send ID to force-delete pending token" + " from list if mint is unavailable." ) return if all: @@ -527,7 +542,8 @@ async def pending(ctx: Context, legacy, number: int, offset: int): int(grouped_proofs[0].time_reserved) ).strftime("%Y-%m-%d %H:%M:%S") print( - f"#{i} Amount: {sum_proofs(grouped_proofs)} sat Time: {reserved_date} ID: {key} Mint: {mint}\n" + f"#{i} Amount: {sum_proofs(grouped_proofs)} sat Time:" + f" {reserved_date} ID: {key} Mint: {mint}\n" ) print(f"{token}\n") @@ -657,7 +673,8 @@ async def wallets(ctx): if w == ctx.obj["WALLET_NAME"]: active_wallet = True print( - f"Wallet: {w}\tBalance: {sum_proofs(wallet.proofs)} sat (available: " + f"Wallet: {w}\tBalance: {sum_proofs(wallet.proofs)} sat" + " (available: " f"{sum_proofs([p for p in wallet.proofs if not p.reserved])} sat){' *' if active_wallet else ''}" ) except Exception: @@ -741,12 +758,14 @@ async def restore(ctx: Context, to: int, batch: int): ret = await get_seed_and_mnemonic(wallet.db) if ret: print( - "Wallet already has a mnemonic. You can't restore an already initialized wallet." + "Wallet already has a mnemonic. You can't restore an already initialized" + " wallet." ) print("To restore a wallet, please delete the wallet directory and try again.") print("") print( - f"The wallet directory is: {os.path.join(settings.cashu_dir, ctx.obj['WALLET_NAME'])}" + "The wallet directory is:" + f" {os.path.join(settings.cashu_dir, ctx.obj['WALLET_NAME'])}" ) return # ask the user for a mnemonic but allow also no input diff --git a/cashu/wallet/cli/cli_helpers.py b/cashu/wallet/cli/cli_helpers.py index 068d2443..e7d12b21 100644 --- a/cashu/wallet/cli/cli_helpers.py +++ b/cashu/wallet/cli/cli_helpers.py @@ -78,7 +78,8 @@ async def print_mint_balances(wallet, show_mints=False): print("") for i, (k, v) in enumerate(mint_balances.items()): print( - f"Mint {i+1}: Balance: {v['available']} sat (pending: {v['balance']-v['available']} sat) URL: {k}" + f"Mint {i+1}: Balance: {v['available']} sat (pending:" + f" {v['balance']-v['available']} sat) URL: {k}" ) print("") diff --git a/cashu/wallet/crud.py b/cashu/wallet/crud.py index 887db759..e229ccf1 100644 --- a/cashu/wallet/crud.py +++ b/cashu/wallet/crud.py @@ -31,11 +31,9 @@ async def get_proofs( db: Database, conn: Optional[Connection] = None, ): - rows = await (conn or db).fetchall( - """ + rows = await (conn or db).fetchall(""" SELECT * from proofs - """ - ) + """) return [Proof(**dict(r)) for r in rows] @@ -43,12 +41,10 @@ async def get_reserved_proofs( db: Database, conn: Optional[Connection] = None, ): - rows = await (conn or db).fetchall( - """ + rows = await (conn or db).fetchall(""" SELECT * from proofs WHERE reserved - """ - ) + """) return [Proof(**r) for r in rows] diff --git a/cashu/wallet/helpers.py b/cashu/wallet/helpers.py index ac71118d..302298d7 100644 --- a/cashu/wallet/helpers.py +++ b/cashu/wallet/helpers.py @@ -195,7 +195,8 @@ async def send( send_proofs = [p] break assert send_proofs, Exception( - f"No proof with this amount found. Available amounts: {set([p.amount for p in wallet.proofs])}" + "No proof with this amount found. Available amounts:" + f" {set([p.amount for p in wallet.proofs])}" ) await wallet.set_reserved(send_proofs, reserved=True) diff --git a/cashu/wallet/migrations.py b/cashu/wallet/migrations.py index 810def7e..061b31c5 100644 --- a/cashu/wallet/migrations.py +++ b/cashu/wallet/migrations.py @@ -2,19 +2,16 @@ async def m000_create_migrations_table(db: Database): - await db.execute( - """ + await db.execute(""" CREATE TABLE IF NOT EXISTS dbversions ( db TEXT PRIMARY KEY, version INT NOT NULL ) - """ - ) + """) async def m001_initial(db: Database): - await db.execute( - f""" + await db.execute(f""" CREATE TABLE IF NOT EXISTS proofs ( amount {db.big_int} NOT NULL, C TEXT NOT NULL, @@ -23,11 +20,9 @@ async def m001_initial(db: Database): UNIQUE (secret) ); - """ - ) + """) - await db.execute( - f""" + await db.execute(f""" CREATE TABLE IF NOT EXISTS proofs_used ( amount {db.big_int} NOT NULL, C TEXT NOT NULL, @@ -36,30 +31,25 @@ async def m001_initial(db: Database): UNIQUE (secret) ); - """ - ) + """) - await db.execute( - """ + await db.execute(""" CREATE VIEW IF NOT EXISTS balance AS SELECT COALESCE(SUM(s), 0) AS balance FROM ( SELECT SUM(amount) AS s FROM proofs WHERE amount > 0 ); - """ - ) + """) - await db.execute( - """ + await db.execute(""" CREATE VIEW IF NOT EXISTS balance_used AS SELECT COALESCE(SUM(s), 0) AS used FROM ( SELECT SUM(amount) AS s FROM proofs_used WHERE amount > 0 ); - """ - ) + """) async def m002_add_proofs_reserved(db: Database): @@ -85,8 +75,7 @@ async def m004_p2sh_locks(db: Database): """ Stores P2SH addresses and unlock scripts. """ - await db.execute( - """ + await db.execute(""" CREATE TABLE IF NOT EXISTS p2sh ( address TEXT NOT NULL, script TEXT NOT NULL, @@ -96,16 +85,14 @@ async def m004_p2sh_locks(db: Database): UNIQUE (address, script, signature) ); - """ - ) + """) async def m005_wallet_keysets(db: Database): """ Stores mint keysets from different mints and epochs. """ - await db.execute( - f""" + await db.execute(f""" CREATE TABLE IF NOT EXISTS keysets ( id TEXT, mint_url TEXT, @@ -117,8 +104,7 @@ async def m005_wallet_keysets(db: Database): UNIQUE (id, mint_url) ); - """ - ) + """) await db.execute("ALTER TABLE proofs ADD COLUMN id TEXT") await db.execute("ALTER TABLE proofs_used ADD COLUMN id TEXT") @@ -128,8 +114,7 @@ async def m006_invoices(db: Database): """ Stores Lightning invoices. """ - await db.execute( - f""" + await db.execute(f""" CREATE TABLE IF NOT EXISTS invoices ( amount INTEGER NOT NULL, pr TEXT NOT NULL, @@ -142,22 +127,19 @@ async def m006_invoices(db: Database): UNIQUE (hash) ); - """ - ) + """) async def m007_nostr(db: Database): """ Stores timestamps of nostr operations. """ - await db.execute( - """ + await db.execute(""" CREATE TABLE IF NOT EXISTS nostr ( type TEXT NOT NULL, last TIMESTAMP DEFAULT NULL ) - """ - ) + """) await db.execute( """ INSERT INTO nostr @@ -182,14 +164,12 @@ async def m009_privatekey_and_determinstic_key_derivation(db: Database): await db.execute("ALTER TABLE keysets ADD COLUMN counter INTEGER DEFAULT 0") await db.execute("ALTER TABLE proofs ADD COLUMN derivation_path TEXT") await db.execute("ALTER TABLE proofs_used ADD COLUMN derivation_path TEXT") - await db.execute( - """ + await db.execute(""" CREATE TABLE IF NOT EXISTS seed ( seed TEXT NOT NULL, mnemonic TEXT NOT NULL, UNIQUE (seed, mnemonic) ); - """ - ) + """) # await db.execute("INSERT INTO secret_derivation (counter) VALUES (0)") diff --git a/cashu/wallet/nostr.py b/cashu/wallet/nostr.py index 1ea1918c..3f508b71 100644 --- a/cashu/wallet/nostr.py +++ b/cashu/wallet/nostr.py @@ -99,8 +99,9 @@ async def receive_nostr( ): if settings.nostr_private_key is None: print( - "Warning: No nostr private key set! You don't have NOSTR_PRIVATE_KEY set in your .env file. " - "I will create a random private key for this session but I will not remember it." + "Warning: No nostr private key set! You don't have NOSTR_PRIVATE_KEY set in" + " your .env file. I will create a random private key for this session but I" + " will not remember it." ) print("") client = NostrClient( diff --git a/cashu/wallet/wallet.py b/cashu/wallet/wallet.py index 61cd606c..8926ffa7 100644 --- a/cashu/wallet/wallet.py +++ b/cashu/wallet/wallet.py @@ -702,7 +702,8 @@ async def _init_private_key(self, from_mnemonic: Optional[str] = None) -> None: else "" ) print( - f'Generated a new mnemonic{wallet_name}. To view it, run "cashu{wallet_command_prefix_str} info --mnemonic".' + f"Generated a new mnemonic{wallet_name}. To view it, run" + f' "cashu{wallet_command_prefix_str} info --mnemonic".' ) elif from_mnemonic: # or use the one provided @@ -1425,7 +1426,8 @@ async def invalidate( if invalidated_proofs: logger.debug( - f"Invalidating {len(invalidated_proofs)} proofs worth {sum_proofs(invalidated_proofs)} sat." + f"Invalidating {len(invalidated_proofs)} proofs worth" + f" {sum_proofs(invalidated_proofs)} sat." ) async with self.db.connect() as conn: @@ -1559,7 +1561,8 @@ async def sign_p2pk_proofs(self, proofs: List[Proof]) -> List[str]: private_key = self.private_key assert private_key.pubkey logger.trace( - f"Signing with private key: {private_key.serialize()} public key: {private_key.pubkey.serialize().hex()}" + f"Signing with private key: {private_key.serialize()} public key:" + f" {private_key.pubkey.serialize().hex()}" ) for proof in proofs: logger.trace(f"Signing proof: {proof}") diff --git a/poetry.lock b/poetry.lock index ccdf37d7..4a3bc9e6 100644 --- a/poetry.lock +++ b/poetry.lock @@ -104,31 +104,42 @@ files = [ [[package]] name = "black" -version = "22.12.0" +version = "23.7.0" description = "The uncompromising code formatter." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "black-22.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9eedd20838bd5d75b80c9f5487dbcb06836a43833a37846cf1d8c1cc01cef59d"}, - {file = "black-22.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:159a46a4947f73387b4d83e87ea006dbb2337eab6c879620a3ba52699b1f4351"}, - {file = "black-22.12.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d30b212bffeb1e252b31dd269dfae69dd17e06d92b87ad26e23890f3efea366f"}, - {file = "black-22.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:7412e75863aa5c5411886804678b7d083c7c28421210180d67dfd8cf1221e1f4"}, - {file = "black-22.12.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c116eed0efb9ff870ded8b62fe9f28dd61ef6e9ddd28d83d7d264a38417dcee2"}, - {file = "black-22.12.0-cp37-cp37m-win_amd64.whl", hash = "sha256:1f58cbe16dfe8c12b7434e50ff889fa479072096d79f0a7f25e4ab8e94cd8350"}, - {file = "black-22.12.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77d86c9f3db9b1bf6761244bc0b3572a546f5fe37917a044e02f3166d5aafa7d"}, - {file = "black-22.12.0-cp38-cp38-win_amd64.whl", hash = "sha256:82d9fe8fee3401e02e79767016b4907820a7dc28d70d137eb397b92ef3cc5bfc"}, - {file = "black-22.12.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:101c69b23df9b44247bd88e1d7e90154336ac4992502d4197bdac35dd7ee3320"}, - {file = "black-22.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:559c7a1ba9a006226f09e4916060982fd27334ae1998e7a38b3f33a37f7a2148"}, - {file = "black-22.12.0-py3-none-any.whl", hash = "sha256:436cc9167dd28040ad90d3b404aec22cedf24a6e4d7de221bec2730ec0c97bcf"}, - {file = "black-22.12.0.tar.gz", hash = "sha256:229351e5a18ca30f447bf724d007f890f97e13af070bb6ad4c0a441cd7596a2f"}, + {file = "black-23.7.0-cp310-cp310-macosx_10_16_arm64.whl", hash = "sha256:5c4bc552ab52f6c1c506ccae05681fab58c3f72d59ae6e6639e8885e94fe2587"}, + {file = "black-23.7.0-cp310-cp310-macosx_10_16_universal2.whl", hash = "sha256:552513d5cd5694590d7ef6f46e1767a4df9af168d449ff767b13b084c020e63f"}, + {file = "black-23.7.0-cp310-cp310-macosx_10_16_x86_64.whl", hash = "sha256:86cee259349b4448adb4ef9b204bb4467aae74a386bce85d56ba4f5dc0da27be"}, + {file = "black-23.7.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:501387a9edcb75d7ae8a4412bb8749900386eaef258f1aefab18adddea1936bc"}, + {file = "black-23.7.0-cp310-cp310-win_amd64.whl", hash = "sha256:fb074d8b213749fa1d077d630db0d5f8cc3b2ae63587ad4116e8a436e9bbe995"}, + {file = "black-23.7.0-cp311-cp311-macosx_10_16_arm64.whl", hash = "sha256:b5b0ee6d96b345a8b420100b7d71ebfdd19fab5e8301aff48ec270042cd40ac2"}, + {file = "black-23.7.0-cp311-cp311-macosx_10_16_universal2.whl", hash = "sha256:893695a76b140881531062d48476ebe4a48f5d1e9388177e175d76234ca247cd"}, + {file = "black-23.7.0-cp311-cp311-macosx_10_16_x86_64.whl", hash = "sha256:c333286dc3ddca6fdff74670b911cccedacb4ef0a60b34e491b8a67c833b343a"}, + {file = "black-23.7.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:831d8f54c3a8c8cf55f64d0422ee875eecac26f5f649fb6c1df65316b67c8926"}, + {file = "black-23.7.0-cp311-cp311-win_amd64.whl", hash = "sha256:7f3bf2dec7d541b4619b8ce526bda74a6b0bffc480a163fed32eb8b3c9aed8ad"}, + {file = "black-23.7.0-cp38-cp38-macosx_10_16_arm64.whl", hash = "sha256:f9062af71c59c004cd519e2fb8f5d25d39e46d3af011b41ab43b9c74e27e236f"}, + {file = "black-23.7.0-cp38-cp38-macosx_10_16_universal2.whl", hash = "sha256:01ede61aac8c154b55f35301fac3e730baf0c9cf8120f65a9cd61a81cfb4a0c3"}, + {file = "black-23.7.0-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:327a8c2550ddc573b51e2c352adb88143464bb9d92c10416feb86b0f5aee5ff6"}, + {file = "black-23.7.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d1c6022b86f83b632d06f2b02774134def5d4d4f1dac8bef16d90cda18ba28a"}, + {file = "black-23.7.0-cp38-cp38-win_amd64.whl", hash = "sha256:27eb7a0c71604d5de083757fbdb245b1a4fae60e9596514c6ec497eb63f95320"}, + {file = "black-23.7.0-cp39-cp39-macosx_10_16_arm64.whl", hash = "sha256:8417dbd2f57b5701492cd46edcecc4f9208dc75529bcf76c514864e48da867d9"}, + {file = "black-23.7.0-cp39-cp39-macosx_10_16_universal2.whl", hash = "sha256:47e56d83aad53ca140da0af87678fb38e44fd6bc0af71eebab2d1f59b1acf1d3"}, + {file = "black-23.7.0-cp39-cp39-macosx_10_16_x86_64.whl", hash = "sha256:25cc308838fe71f7065df53aedd20327969d05671bac95b38fdf37ebe70ac087"}, + {file = "black-23.7.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:642496b675095d423f9b8448243336f8ec71c9d4d57ec17bf795b67f08132a91"}, + {file = "black-23.7.0-cp39-cp39-win_amd64.whl", hash = "sha256:ad0014efc7acf0bd745792bd0d8857413652979200ab924fbf239062adc12491"}, + {file = "black-23.7.0-py3-none-any.whl", hash = "sha256:9fd59d418c60c0348505f2ddf9609c1e1de8e7493eab96198fc89d9f865e7a96"}, + {file = "black-23.7.0.tar.gz", hash = "sha256:022a582720b0d9480ed82576c920a8c1dde97cc38ff11d8d8859b3bd6ca9eedb"}, ] [package.dependencies] click = ">=8.0.0" mypy-extensions = ">=0.4.3" +packaging = ">=22.0" pathspec = ">=0.9.0" platformdirs = ">=2" -tomli = {version = ">=1.1.0", markers = "python_full_version < \"3.11.0a7\""} +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""} [package.extras] @@ -614,22 +625,6 @@ files = [ docs = ["furo (>=2023.5.20)", "sphinx (>=7.0.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] testing = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "diff-cover (>=7.5)", "pytest (>=7.3.1)", "pytest-cov (>=4.1)", "pytest-mock (>=3.10)", "pytest-timeout (>=2.1)"] -[[package]] -name = "flake8" -version = "6.0.0" -description = "the modular source code checker: pep8 pyflakes and co" -optional = false -python-versions = ">=3.8.1" -files = [ - {file = "flake8-6.0.0-py2.py3-none-any.whl", hash = "sha256:3833794e27ff64ea4e9cf5d410082a8b97ff1a06c16aa3d2027339cd0f1195c7"}, - {file = "flake8-6.0.0.tar.gz", hash = "sha256:c61007e76655af75e6785a931f452915b371dc48f56efd765247c8fe68f2b181"}, -] - -[package.dependencies] -mccabe = ">=0.7.0,<0.8.0" -pycodestyle = ">=2.10.0,<2.11.0" -pyflakes = ">=3.0.0,<3.1.0" - [[package]] name = "h11" version = "0.12.0" @@ -740,23 +735,6 @@ files = [ {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, ] -[[package]] -name = "isort" -version = "5.12.0" -description = "A Python utility / library to sort Python imports." -optional = false -python-versions = ">=3.8.0" -files = [ - {file = "isort-5.12.0-py3-none-any.whl", hash = "sha256:f84c2818376e66cf843d497486ea8fed8700b340f308f076c6fb1229dff318b6"}, - {file = "isort-5.12.0.tar.gz", hash = "sha256:8bef7dde241278824a6d83f44a544709b065191b95b6e50894bdc722fcba0504"}, -] - -[package.extras] -colors = ["colorama (>=0.4.3)"] -pipfile-deprecated-finder = ["pip-shims (>=0.5.2)", "pipreqs", "requirementslib"] -plugins = ["setuptools"] -requirements-deprecated-finder = ["pip-api", "pipreqs"] - [[package]] name = "loguru" version = "0.6.0" @@ -795,17 +773,6 @@ docs = ["alabaster (==0.7.13)", "autodocsumm (==0.2.11)", "sphinx (==7.0.1)", "s lint = ["flake8 (==6.0.0)", "flake8-bugbear (==23.7.10)", "mypy (==1.4.1)", "pre-commit (>=2.4,<4.0)"] tests = ["pytest", "pytz", "simplejson"] -[[package]] -name = "mccabe" -version = "0.7.0" -description = "McCabe checker, plugin for flake8" -optional = false -python-versions = ">=3.6" -files = [ - {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, - {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, -] - [[package]] name = "mnemonic" version = "0.20" @@ -1039,17 +1006,6 @@ files = [ {file = "psycopg2_binary-2.9.6-cp39-cp39-win_amd64.whl", hash = "sha256:f6a88f384335bb27812293fdb11ac6aee2ca3f51d3c7820fe03de0a304ab6249"}, ] -[[package]] -name = "pycodestyle" -version = "2.10.0" -description = "Python style guide checker" -optional = false -python-versions = ">=3.6" -files = [ - {file = "pycodestyle-2.10.0-py2.py3-none-any.whl", hash = "sha256:8a4eaf0d0495c7395bdab3589ac2db602797d76207242c17d470186815706610"}, - {file = "pycodestyle-2.10.0.tar.gz", hash = "sha256:347187bdb476329d98f695c213d7295a846d1152ff4fe9bacb8a9590b8ee7053"}, -] - [[package]] name = "pycparser" version = "2.21" @@ -1154,17 +1110,6 @@ typing-extensions = ">=4.2.0" dotenv = ["python-dotenv (>=0.10.4)"] email = ["email-validator (>=1.0.3)"] -[[package]] -name = "pyflakes" -version = "3.0.1" -description = "passive checker of Python programs" -optional = false -python-versions = ">=3.6" -files = [ - {file = "pyflakes-3.0.1-py2.py3-none-any.whl", hash = "sha256:ec55bf7fe21fff7f1ad2f7da62363d749e2a470500eab1b555334b67aa1ef8cf"}, - {file = "pyflakes-3.0.1.tar.gz", hash = "sha256:ec8b276a6b60bd80defed25add7e439881c19e64850afd9b346283d4165fd0fd"}, -] - [[package]] name = "pysocks" version = "1.7.1" @@ -1363,6 +1308,32 @@ idna = {version = "*", optional = true, markers = "extra == \"idna2008\""} [package.extras] idna2008 = ["idna"] +[[package]] +name = "ruff" +version = "0.0.284" +description = "An extremely fast Python linter, written in Rust." +optional = false +python-versions = ">=3.7" +files = [ + {file = "ruff-0.0.284-py3-none-macosx_10_7_x86_64.whl", hash = "sha256:8b949084941232e2c27f8d12c78c5a6a010927d712ecff17231ee1a8371c205b"}, + {file = "ruff-0.0.284-py3-none-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:a3930d66b35e4dc96197422381dff2a4e965e9278b5533e71ae8474ef202fab0"}, + {file = "ruff-0.0.284-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d1f7096038961d8bc3b956ee69d73826843eb5b39a5fa4ee717ed473ed69c95"}, + {file = "ruff-0.0.284-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bcaf85907fc905d838f46490ee15f04031927bbea44c478394b0bfdeadc27362"}, + {file = "ruff-0.0.284-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3660b85a9d84162a055f1add334623ae2d8022a84dcd605d61c30a57b436c32"}, + {file = "ruff-0.0.284-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:0a3218458b140ea794da72b20ea09cbe13c4c1cdb7ac35e797370354628f4c05"}, + {file = "ruff-0.0.284-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b2fe880cff13fffd735387efbcad54ba0ff1272bceea07f86852a33ca71276f4"}, + {file = "ruff-0.0.284-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d1d098ea74d0ce31478765d1f8b4fbdbba2efc532397b5c5e8e5ea0c13d7e5ae"}, + {file = "ruff-0.0.284-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c4c79ae3308e308b94635cd57a369d1e6f146d85019da2fbc63f55da183ee29b"}, + {file = "ruff-0.0.284-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:f86b2b1e7033c00de45cc176cf26778650fb8804073a0495aca2f674797becbb"}, + {file = "ruff-0.0.284-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:e37e086f4d623c05cd45a6fe5006e77a2b37d57773aad96b7802a6b8ecf9c910"}, + {file = "ruff-0.0.284-py3-none-musllinux_1_2_i686.whl", hash = "sha256:d29dfbe314e1131aa53df213fdfea7ee874dd96ea0dd1471093d93b59498384d"}, + {file = "ruff-0.0.284-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:88295fd649d0aa1f1271441df75bf06266a199497afd239fd392abcfd75acd7e"}, + {file = "ruff-0.0.284-py3-none-win32.whl", hash = "sha256:735cd62fccc577032a367c31f6a9de7c1eb4c01fa9a2e60775067f44f3fc3091"}, + {file = "ruff-0.0.284-py3-none-win_amd64.whl", hash = "sha256:f67ed868d79fbcc61ad0fa034fe6eed2e8d438d32abce9c04b7c4c1464b2cf8e"}, + {file = "ruff-0.0.284-py3-none-win_arm64.whl", hash = "sha256:1292cfc764eeec3cde35b3a31eae3f661d86418b5e220f5d5dba1c27a6eccbb6"}, + {file = "ruff-0.0.284.tar.gz", hash = "sha256:ebd3cc55cd499d326aac17a331deaea29bea206e01c08862f9b5c6e93d77a491"}, +] + [[package]] name = "secp256k1" version = "0.14.0" @@ -1672,4 +1643,4 @@ pgsql = ["psycopg2-binary"] [metadata] lock-version = "2.0" python-versions = "^3.8.1" -content-hash = "7bc36d84b841a4799da7a9f631d90195a569d3bf38dd5b4a7ed47a5901940d88" +content-hash = "83e8f09ebad4bca75c90591fbe0c50d0acf9d19edf6e30437e91fded95cd88c4" diff --git a/pyproject.toml b/pyproject.toml index ee79539e..e3a58473 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,13 +39,12 @@ pgsql = ["psycopg2-binary"] [tool.poetry.group.dev.dependencies] mypy = "^0.971" -black = {version = "^22.8.0", allow-prereleases = true} -isort = "^5.10.1" pytest-asyncio = "^0.19.0" pytest-cov = "^4.0.0" pytest = "^7.4.0" -flake8 = "^6.0.0" pre-commit = "^3.3.3" +ruff = "^0.0.284" +black = "^23.7.0" [build-system] requires = ["poetry-core>=1.0.0"] @@ -55,3 +54,62 @@ build-backend = "poetry.core.masonry.api" mint = "cashu.mint.main:main" cashu = "cashu.wallet.cli.cli:cli" wallet-test = "tests.test_wallet:test" + + +[tool.black] +line-length = 88 + +# previously experimental-string-processing = true +# this should autoformat string properly but does not work +preview = true + + +[tool.ruff] +# Same as Black. but black has a 10% overflow rule +line-length = 150 + +# Enable pycodestyle (`E`) and Pyflakes (`F`) codes by default. +# (`I`) means isorting +select = ["E", "F", "I"] +ignore = [] + +# Allow autofix for all enabled rules (when `--fix`) is provided. +fixable = ["ALL"] +unfixable = [] + +# Exclude a variety of commonly ignored directories. +exclude = [ + "cashu/nostr", + "cashu/core/bolt11.py", + ".bzr", + ".direnv", + ".eggs", + ".git", + ".git-rewrite", + ".hg", + ".mypy_cache", + ".nox", + ".pants.d", + ".pytype", + ".ruff_cache", + ".svn", + ".tox", + ".venv", + "__pypackages__", + "_build", + "buck-out", + "build", + "dist", + "node_modules", + "venv", +] + +# Allow unused variables when underscore-prefixed. +dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$" + +# Assume Python 3.8 +# target-version = "py38" + +[tool.ruff.mccabe] +# Unlike Flake8, default to a complexity level of 10. +max-complexity = 10 diff --git a/tests/test_wallet.py b/tests/test_wallet.py index dc2d8507..c33eee12 100644 --- a/tests/test_wallet.py +++ b/tests/test_wallet.py @@ -94,7 +94,7 @@ async def test_get_keys(wallet1: Wallet): assert len(wallet1.keys.public_keys) == settings.max_order keyset = await wallet1._get_keys(wallet1.url) assert keyset.id is not None - assert type(keyset.id) == str + assert isinstance(keyset.id, str) assert len(keyset.id) > 0 @@ -244,9 +244,7 @@ async def test_duplicate_proofs_double_spent(wallet1: Wallet): @pytest.mark.asyncio async def test_send_and_redeem(wallet1: Wallet, wallet2: Wallet): await wallet1.mint(64) - _, spendable_proofs = await wallet1.split_to_send( # type: ignore - wallet1.proofs, 32, set_reserved=True - ) + _, spendable_proofs = await wallet1.split_to_send(wallet1.proofs, 32, set_reserved=True) # type: ignore await wallet2.redeem(spendable_proofs) assert wallet2.balance == 32 @@ -325,7 +323,8 @@ async def test_token_state(wallet1: Wallet): @pytest.mark.asyncio async def test_bump_secret_derivation(wallet3: Wallet): await wallet3._init_private_key( - "half depart obvious quality work element tank gorilla view sugar picture humble" + "half depart obvious quality work element tank gorilla view sugar picture" + " humble" ) secrets1, rs1, derivaion_paths1 = await wallet3.generate_n_secrets(5) secrets2, rs2, derivaion_paths2 = await wallet3.generate_secrets_from_to(0, 4) @@ -351,7 +350,8 @@ async def test_bump_secret_derivation(wallet3: Wallet): @pytest.mark.asyncio async def test_bump_secret_derivation_two_steps(wallet3: Wallet): await wallet3._init_private_key( - "half depart obvious quality work element tank gorilla view sugar picture humble" + "half depart obvious quality work element tank gorilla view sugar picture" + " humble" ) secrets1_1, rs1_1, derivaion_paths1 = await wallet3.generate_n_secrets(2) secrets1_2, rs1_2, derivaion_paths2 = await wallet3.generate_n_secrets(3) @@ -365,7 +365,8 @@ async def test_bump_secret_derivation_two_steps(wallet3: Wallet): @pytest.mark.asyncio async def test_generate_secrets_from_to(wallet3: Wallet): await wallet3._init_private_key( - "half depart obvious quality work element tank gorilla view sugar picture humble" + "half depart obvious quality work element tank gorilla view sugar picture" + " humble" ) secrets1, rs1, derivaion_paths1 = await wallet3.generate_secrets_from_to(0, 4) assert len(secrets1) == 5 @@ -392,7 +393,8 @@ async def test_restore_wallet_after_mint(wallet3: Wallet): async def test_restore_wallet_with_invalid_mnemonic(wallet3: Wallet): await assert_err( wallet3._init_private_key( - "half depart obvious quality work element tank gorilla view sugar picture picture" + "half depart obvious quality work element tank gorilla view sugar picture" + " picture" ), "Invalid mnemonic", ) @@ -401,16 +403,15 @@ async def test_restore_wallet_with_invalid_mnemonic(wallet3: Wallet): @pytest.mark.asyncio async def test_restore_wallet_after_split_to_send(wallet3: Wallet): await wallet3._init_private_key( - "half depart obvious quality work element tank gorilla view sugar picture humble" + "half depart obvious quality work element tank gorilla view sugar picture" + " humble" ) await reset_wallet_db(wallet3) await wallet3.mint(64) assert wallet3.balance == 64 - _, spendable_proofs = await wallet3.split_to_send( # type: ignore - wallet3.proofs, 32, set_reserved=True - ) + _, spendable_proofs = await wallet3.split_to_send(wallet3.proofs, 32, set_reserved=True) # type: ignore await reset_wallet_db(wallet3) await wallet3.load_proofs() @@ -432,9 +433,7 @@ async def test_restore_wallet_after_send_and_receive(wallet3: Wallet, wallet2: W await wallet3.mint(64) assert wallet3.balance == 64 - _, spendable_proofs = await wallet3.split_to_send( # type: ignore - wallet3.proofs, 32, set_reserved=True - ) + _, spendable_proofs = await wallet3.split_to_send(wallet3.proofs, 32, set_reserved=True) # type: ignore await wallet2.redeem(spendable_proofs) @@ -465,16 +464,15 @@ def add(self, proofs: List[Proof]) -> None: @pytest.mark.asyncio async def test_restore_wallet_after_send_and_self_receive(wallet3: Wallet): await wallet3._init_private_key( - "lucky broken tell exhibit shuffle tomato ethics virus rabbit spread measure text" + "lucky broken tell exhibit shuffle tomato ethics virus rabbit spread measure" + " text" ) await reset_wallet_db(wallet3) await wallet3.mint(64) assert wallet3.balance == 64 - _, spendable_proofs = await wallet3.split_to_send( # type: ignore - wallet3.proofs, 32, set_reserved=True - ) + _, spendable_proofs = await wallet3.split_to_send(wallet3.proofs, 32, set_reserved=True) # type: ignore await wallet3.redeem(spendable_proofs) @@ -500,9 +498,7 @@ async def test_restore_wallet_after_send_twice( box.add(wallet3.proofs) assert wallet3.balance == 2 - keep_proofs, spendable_proofs = await wallet3.split_to_send( # type: ignore - wallet3.proofs, 1, set_reserved=True - ) + keep_proofs, spendable_proofs = await wallet3.split_to_send(wallet3.proofs, 1, set_reserved=True) # type: ignore box.add(wallet3.proofs) assert wallet3.available_balance == 1 await wallet3.redeem(spendable_proofs) @@ -522,9 +518,7 @@ async def test_restore_wallet_after_send_twice( # again - _, spendable_proofs = await wallet3.split_to_send( # type: ignore - wallet3.proofs, 1, set_reserved=True - ) + _, spendable_proofs = await wallet3.split_to_send(wallet3.proofs, 1, set_reserved=True) # type: ignore box.add(wallet3.proofs) assert wallet3.available_balance == 1 @@ -557,9 +551,7 @@ async def test_restore_wallet_after_send_and_self_receive_nonquadratic_value( box.add(wallet3.proofs) assert wallet3.balance == 64 - keep_proofs, spendable_proofs = await wallet3.split_to_send( # type: ignore - wallet3.proofs, 10, set_reserved=True - ) + keep_proofs, spendable_proofs = await wallet3.split_to_send(wallet3.proofs, 10, set_reserved=True) # type: ignore box.add(wallet3.proofs) assert wallet3.available_balance == 64 - 10 @@ -579,9 +571,7 @@ async def test_restore_wallet_after_send_and_self_receive_nonquadratic_value( # again - _, spendable_proofs = await wallet3.split_to_send( # type: ignore - wallet3.proofs, 12, set_reserved=True - ) + _, spendable_proofs = await wallet3.split_to_send(wallet3.proofs, 12, set_reserved=True) # type: ignore assert wallet3.available_balance == 64 - 12 await wallet3.redeem(spendable_proofs) From 68cf6d6f0706d05bdd16070c3a89f518cfca9a14 Mon Sep 17 00:00:00 2001 From: sihamon <126967444+sihamon@users.noreply.github.com> Date: Thu, 24 Aug 2023 09:51:08 +0200 Subject: [PATCH 3/9] Show all mints in cashu info (#299) --- cashu/wallet/api/responses.py | 2 +- cashu/wallet/api/router.py | 11 ++++++-- cashu/wallet/cli/cli.py | 50 +++++++++++++++++++++-------------- cashu/wallet/helpers.py | 9 +++++++ 4 files changed, 49 insertions(+), 23 deletions(-) diff --git a/cashu/wallet/api/responses.py b/cashu/wallet/api/responses.py index 931aa56d..625a78af 100644 --- a/cashu/wallet/api/responses.py +++ b/cashu/wallet/api/responses.py @@ -74,7 +74,7 @@ class InfoResponse(BaseModel): wallet: str debug: bool cashu_dir: str - mint_url: str + mint_urls: List[str] = [] settings: Optional[str] tor: bool nostr_public_key: Optional[str] = None diff --git a/cashu/wallet/api/router.py b/cashu/wallet/api/router.py index 3a671b6d..0b96fa81 100644 --- a/cashu/wallet/api/router.py +++ b/cashu/wallet/api/router.py @@ -14,7 +14,13 @@ from ...nostr.nostr.client.client import NostrClient from ...tor.tor import TorProxy from ...wallet.crud import get_lightning_invoices, get_reserved_proofs, get_unused_locks -from ...wallet.helpers import deserialize_token_from_string, init_wallet, receive, send +from ...wallet.helpers import ( + deserialize_token_from_string, + init_wallet, + list_mints, + receive, + send, +) from ...wallet.nostr import receive_nostr, send_nostr from ...wallet.wallet import Wallet as Wallet from .api_helpers import verify_mints @@ -427,12 +433,13 @@ async def info(): else: nostr_public_key = None nostr_relays = [] + mint_list = await list_mints(wallet) return InfoResponse( version=settings.version, wallet=wallet.name, debug=settings.debug, cashu_dir=settings.cashu_dir, - mint_url=settings.mint_url, + mint_urls=mint_list, settings=settings.env_file, tor=settings.tor, nostr_public_key=nostr_public_key, diff --git a/cashu/wallet/cli/cli.py b/cashu/wallet/cli/cli.py index 9acf2b29..5dec8f1a 100644 --- a/cashu/wallet/cli/cli.py +++ b/cashu/wallet/cli/cli.py @@ -28,7 +28,13 @@ from ...wallet.wallet import Wallet as Wallet from ..api.api_server import start_api_server from ..cli.cli_helpers import get_mint_wallet, print_mint_balances, verify_mint -from ..helpers import deserialize_token_from_string, init_wallet, receive, send +from ..helpers import ( + deserialize_token_from_string, + init_wallet, + list_mints, + receive, + send, +) from ..nostr import receive_nostr, send_nostr @@ -708,26 +714,30 @@ async def info(ctx: Context, mint: bool, mnemonic: bool): print(f"Socks proxy: {settings.socks_proxy}") if settings.http_proxy: print(f"HTTP proxy: {settings.http_proxy}") - print(f"Mint URL: {ctx.obj['HOST']}") + mint_list = await list_mints(wallet) + print(f"Mint URLs: {mint_list}") if mint: - mint_info: dict = (await wallet._load_mint_info()).dict() - print("") - print("Mint information:") - print("") - if mint_info: - print(f"Mint name: {mint_info['name']}") - if mint_info["description"]: - print(f"Description: {mint_info['description']}") - if mint_info["description_long"]: - print(f"Long description: {mint_info['description_long']}") - if mint_info["contact"]: - print(f"Contact: {mint_info['contact']}") - if mint_info["version"]: - print(f"Version: {mint_info['version']}") - if mint_info["motd"]: - print(f"Message of the day: {mint_info['motd']}") - if mint_info["parameter"]: - print(f"Parameter: {mint_info['parameter']}") + for mint_url in mint_list: + wallet.url = mint_url + mint_info: dict = (await wallet._load_mint_info()).dict() + print("") + print("Mint information:") + print("") + print(f"Mint URL: {mint_url}") + if mint_info: + print(f"Mint name: {mint_info['name']}") + if mint_info["description"]: + print(f"Description: {mint_info['description']}") + if mint_info["description_long"]: + print(f"Long description: {mint_info['description_long']}") + if mint_info["contact"]: + print(f"Contact: {mint_info['contact']}") + if mint_info["version"]: + print(f"Version: {mint_info['version']}") + if mint_info["motd"]: + print(f"Message of the day: {mint_info['motd']}") + if mint_info["parameter"]: + print(f"Parameter: {mint_info['parameter']}") if mnemonic: assert wallet.mnemonic diff --git a/cashu/wallet/helpers.py b/cashu/wallet/helpers.py index 302298d7..d6a1d289 100644 --- a/cashu/wallet/helpers.py +++ b/cashu/wallet/helpers.py @@ -26,6 +26,15 @@ async def init_wallet(wallet: Wallet, load_proofs: bool = True): await wallet.load_proofs(reload=True) +async def list_mints(wallet: Wallet): + await wallet.load_proofs() + balances = await wallet.balance_per_minturl() + mints = list(balances.keys()) + if wallet.url not in mints: + mints.append(wallet.url) + return mints + + async def redeem_TokenV3_multimint(wallet: Wallet, token: TokenV3): """ Helper function to iterate thruogh a token with multiple mints and redeem them from From 4f5d3c66febdabcef1062c03c6806376ea6a000f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Thu, 24 Aug 2023 10:19:44 +0200 Subject: [PATCH 4/9] quickfix ruff (#303) --- tests/test_mint.py | 2 +- tests/test_wallet.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_mint.py b/tests/test_mint.py index 2a5e22db..ae9ed4a9 100644 --- a/tests/test_mint.py +++ b/tests/test_mint.py @@ -60,7 +60,7 @@ async def test_keysets(ledger: Ledger): @pytest.mark.asyncio async def test_get_keyset(ledger: Ledger): keyset = ledger.get_keyset() - assert type(keyset) == dict + assert isinstance(keyset, dict) assert len(keyset) == settings.max_order diff --git a/tests/test_wallet.py b/tests/test_wallet.py index c33eee12..c5bd9601 100644 --- a/tests/test_wallet.py +++ b/tests/test_wallet.py @@ -129,7 +129,7 @@ async def test_get_nonexistent_keyset(wallet1: Wallet): @pytest.mark.asyncio async def test_get_keyset_ids(wallet1: Wallet): keyset = await wallet1._get_keyset_ids(wallet1.url) - assert type(keyset) == list + assert isinstance(keyset, list) assert len(keyset) > 0 assert keyset[-1] == wallet1.keyset_id From e374d32df7ecdd51fa00af4f945b6a16b86b3ca7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Thu, 24 Aug 2023 11:09:07 +0200 Subject: [PATCH 5/9] [CHORE] updating dependencies, mainly fastapi (#302) * [CHORE] updating dependencies, mainly fastapi i updated all lib that i could. :) test seem to pass downgrade uvicorn for mypy to pass chore fixup formatting * make flake8 didnt flake tests --- cashu/mint/app.py | 6 +- poetry.lock | 570 ++++++++++++++++++++++--------------------- pyproject.toml | 31 +-- requirements.txt | 101 ++++---- tests/test_wallet.py | 4 +- 5 files changed, 360 insertions(+), 352 deletions(-) diff --git a/cashu/mint/app.py b/cashu/mint/app.py index 412cd907..078a939f 100644 --- a/cashu/mint/app.py +++ b/cashu/mint/app.py @@ -36,19 +36,19 @@ def configure_logger() -> None: class Formatter: def __init__(self): self.padding = 0 - self.minimal_fmt: str = ( + self.minimal_fmt = ( "{time:YYYY-MM-DD HH:mm:ss.SS} |" " {level} | {message}\n" ) if settings.debug: - self.fmt: str = ( + self.fmt = ( "{time:YYYY-MM-DD HH:mm:ss.SS} | {level:" " <4} |" " {name}:{function}:{line}" " | {message}\n" ) else: - self.fmt: str = self.minimal_fmt + self.fmt = self.minimal_fmt def format(self, record): function = "{function}".format(**record) diff --git a/poetry.lock b/poetry.lock index 4a3bc9e6..33e4df0c 100644 --- a/poetry.lock +++ b/poetry.lock @@ -237,13 +237,13 @@ pycparser = "*" [[package]] name = "cfgv" -version = "3.3.1" +version = "3.4.0" description = "Validate configuration and produce human readable error messages." optional = false -python-versions = ">=3.6.1" +python-versions = ">=3.8" files = [ - {file = "cfgv-3.3.1-py2.py3-none-any.whl", hash = "sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426"}, - {file = "cfgv-3.3.1.tar.gz", hash = "sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736"}, + {file = "cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9"}, + {file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"}, ] [[package]] @@ -332,13 +332,13 @@ files = [ [[package]] name = "click" -version = "8.1.6" +version = "8.1.7" description = "Composable command line interface toolkit" optional = false python-versions = ">=3.7" files = [ - {file = "click-8.1.6-py3-none-any.whl", hash = "sha256:fa244bb30b3b5ee2cae3da8f55c9e5e0c0e86093306301fb418eb9dc40fbded5"}, - {file = "click-8.1.6.tar.gz", hash = "sha256:48ee849951919527a045bfe3bf7baa8a959c423134e1a5b98c05c20ba75a1cbd"}, + {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, + {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, ] [package.dependencies] @@ -412,71 +412,63 @@ files = [ [[package]] name = "coverage" -version = "7.2.7" +version = "7.3.0" description = "Code coverage measurement for Python" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "coverage-7.2.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d39b5b4f2a66ccae8b7263ac3c8170994b65266797fb96cbbfd3fb5b23921db8"}, - {file = "coverage-7.2.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6d040ef7c9859bb11dfeb056ff5b3872436e3b5e401817d87a31e1750b9ae2fb"}, - {file = "coverage-7.2.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba90a9563ba44a72fda2e85302c3abc71c5589cea608ca16c22b9804262aaeb6"}, - {file = "coverage-7.2.7-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7d9405291c6928619403db1d10bd07888888ec1abcbd9748fdaa971d7d661b2"}, - {file = "coverage-7.2.7-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31563e97dae5598556600466ad9beea39fb04e0229e61c12eaa206e0aa202063"}, - {file = "coverage-7.2.7-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ebba1cd308ef115925421d3e6a586e655ca5a77b5bf41e02eb0e4562a111f2d1"}, - {file = "coverage-7.2.7-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:cb017fd1b2603ef59e374ba2063f593abe0fc45f2ad9abdde5b4d83bd922a353"}, - {file = "coverage-7.2.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d62a5c7dad11015c66fbb9d881bc4caa5b12f16292f857842d9d1871595f4495"}, - {file = "coverage-7.2.7-cp310-cp310-win32.whl", hash = "sha256:ee57190f24fba796e36bb6d3aa8a8783c643d8fa9760c89f7a98ab5455fbf818"}, - {file = "coverage-7.2.7-cp310-cp310-win_amd64.whl", hash = "sha256:f75f7168ab25dd93110c8a8117a22450c19976afbc44234cbf71481094c1b850"}, - {file = "coverage-7.2.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:06a9a2be0b5b576c3f18f1a241f0473575c4a26021b52b2a85263a00f034d51f"}, - {file = "coverage-7.2.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5baa06420f837184130752b7c5ea0808762083bf3487b5038d68b012e5937dbe"}, - {file = "coverage-7.2.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fdec9e8cbf13a5bf63290fc6013d216a4c7232efb51548594ca3631a7f13c3a3"}, - {file = "coverage-7.2.7-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:52edc1a60c0d34afa421c9c37078817b2e67a392cab17d97283b64c5833f427f"}, - {file = "coverage-7.2.7-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63426706118b7f5cf6bb6c895dc215d8a418d5952544042c8a2d9fe87fcf09cb"}, - {file = "coverage-7.2.7-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:afb17f84d56068a7c29f5fa37bfd38d5aba69e3304af08ee94da8ed5b0865833"}, - {file = "coverage-7.2.7-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:48c19d2159d433ccc99e729ceae7d5293fbffa0bdb94952d3579983d1c8c9d97"}, - {file = "coverage-7.2.7-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0e1f928eaf5469c11e886fe0885ad2bf1ec606434e79842a879277895a50942a"}, - {file = "coverage-7.2.7-cp311-cp311-win32.whl", hash = "sha256:33d6d3ea29d5b3a1a632b3c4e4f4ecae24ef170b0b9ee493883f2df10039959a"}, - {file = "coverage-7.2.7-cp311-cp311-win_amd64.whl", hash = "sha256:5b7540161790b2f28143191f5f8ec02fb132660ff175b7747b95dcb77ac26562"}, - {file = "coverage-7.2.7-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f2f67fe12b22cd130d34d0ef79206061bfb5eda52feb6ce0dba0644e20a03cf4"}, - {file = "coverage-7.2.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a342242fe22407f3c17f4b499276a02b01e80f861f1682ad1d95b04018e0c0d4"}, - {file = "coverage-7.2.7-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:171717c7cb6b453aebac9a2ef603699da237f341b38eebfee9be75d27dc38e01"}, - {file = "coverage-7.2.7-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49969a9f7ffa086d973d91cec8d2e31080436ef0fb4a359cae927e742abfaaa6"}, - {file = "coverage-7.2.7-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b46517c02ccd08092f4fa99f24c3b83d8f92f739b4657b0f146246a0ca6a831d"}, - {file = "coverage-7.2.7-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:a3d33a6b3eae87ceaefa91ffdc130b5e8536182cd6dfdbfc1aa56b46ff8c86de"}, - {file = "coverage-7.2.7-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:976b9c42fb2a43ebf304fa7d4a310e5f16cc99992f33eced91ef6f908bd8f33d"}, - {file = "coverage-7.2.7-cp312-cp312-win32.whl", hash = "sha256:8de8bb0e5ad103888d65abef8bca41ab93721647590a3f740100cd65c3b00511"}, - {file = "coverage-7.2.7-cp312-cp312-win_amd64.whl", hash = "sha256:9e31cb64d7de6b6f09702bb27c02d1904b3aebfca610c12772452c4e6c21a0d3"}, - {file = "coverage-7.2.7-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:58c2ccc2f00ecb51253cbe5d8d7122a34590fac9646a960d1430d5b15321d95f"}, - {file = "coverage-7.2.7-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d22656368f0e6189e24722214ed8d66b8022db19d182927b9a248a2a8a2f67eb"}, - {file = "coverage-7.2.7-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a895fcc7b15c3fc72beb43cdcbdf0ddb7d2ebc959edac9cef390b0d14f39f8a9"}, - {file = "coverage-7.2.7-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e84606b74eb7de6ff581a7915e2dab7a28a0517fbe1c9239eb227e1354064dcd"}, - {file = "coverage-7.2.7-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:0a5f9e1dbd7fbe30196578ca36f3fba75376fb99888c395c5880b355e2875f8a"}, - {file = "coverage-7.2.7-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:419bfd2caae268623dd469eff96d510a920c90928b60f2073d79f8fe2bbc5959"}, - {file = "coverage-7.2.7-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2aee274c46590717f38ae5e4650988d1af340fe06167546cc32fe2f58ed05b02"}, - {file = "coverage-7.2.7-cp37-cp37m-win32.whl", hash = "sha256:61b9a528fb348373c433e8966535074b802c7a5d7f23c4f421e6c6e2f1697a6f"}, - {file = "coverage-7.2.7-cp37-cp37m-win_amd64.whl", hash = "sha256:b1c546aca0ca4d028901d825015dc8e4d56aac4b541877690eb76490f1dc8ed0"}, - {file = "coverage-7.2.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:54b896376ab563bd38453cecb813c295cf347cf5906e8b41d340b0321a5433e5"}, - {file = "coverage-7.2.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3d376df58cc111dc8e21e3b6e24606b5bb5dee6024f46a5abca99124b2229ef5"}, - {file = "coverage-7.2.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e330fc79bd7207e46c7d7fd2bb4af2963f5f635703925543a70b99574b0fea9"}, - {file = "coverage-7.2.7-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e9d683426464e4a252bf70c3498756055016f99ddaec3774bf368e76bbe02b6"}, - {file = "coverage-7.2.7-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d13c64ee2d33eccf7437961b6ea7ad8673e2be040b4f7fd4fd4d4d28d9ccb1e"}, - {file = "coverage-7.2.7-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b7aa5f8a41217360e600da646004f878250a0d6738bcdc11a0a39928d7dc2050"}, - {file = "coverage-7.2.7-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8fa03bce9bfbeeef9f3b160a8bed39a221d82308b4152b27d82d8daa7041fee5"}, - {file = "coverage-7.2.7-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:245167dd26180ab4c91d5e1496a30be4cd721a5cf2abf52974f965f10f11419f"}, - {file = "coverage-7.2.7-cp38-cp38-win32.whl", hash = "sha256:d2c2db7fd82e9b72937969bceac4d6ca89660db0a0967614ce2481e81a0b771e"}, - {file = "coverage-7.2.7-cp38-cp38-win_amd64.whl", hash = "sha256:2e07b54284e381531c87f785f613b833569c14ecacdcb85d56b25c4622c16c3c"}, - {file = "coverage-7.2.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:537891ae8ce59ef63d0123f7ac9e2ae0fc8b72c7ccbe5296fec45fd68967b6c9"}, - {file = "coverage-7.2.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:06fb182e69f33f6cd1d39a6c597294cff3143554b64b9825d1dc69d18cc2fff2"}, - {file = "coverage-7.2.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:201e7389591af40950a6480bd9edfa8ed04346ff80002cec1a66cac4549c1ad7"}, - {file = "coverage-7.2.7-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f6951407391b639504e3b3be51b7ba5f3528adbf1a8ac3302b687ecababf929e"}, - {file = "coverage-7.2.7-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f48351d66575f535669306aa7d6d6f71bc43372473b54a832222803eb956fd1"}, - {file = "coverage-7.2.7-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b29019c76039dc3c0fd815c41392a044ce555d9bcdd38b0fb60fb4cd8e475ba9"}, - {file = "coverage-7.2.7-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:81c13a1fc7468c40f13420732805a4c38a105d89848b7c10af65a90beff25250"}, - {file = "coverage-7.2.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:975d70ab7e3c80a3fe86001d8751f6778905ec723f5b110aed1e450da9d4b7f2"}, - {file = "coverage-7.2.7-cp39-cp39-win32.whl", hash = "sha256:7ee7d9d4822c8acc74a5e26c50604dff824710bc8de424904c0982e25c39c6cb"}, - {file = "coverage-7.2.7-cp39-cp39-win_amd64.whl", hash = "sha256:eb393e5ebc85245347950143969b241d08b52b88a3dc39479822e073a1a8eb27"}, - {file = "coverage-7.2.7-pp37.pp38.pp39-none-any.whl", hash = "sha256:b7b4c971f05e6ae490fef852c218b0e79d4e52f79ef0c8475566584a8fb3e01d"}, - {file = "coverage-7.2.7.tar.gz", hash = "sha256:924d94291ca674905fe9481f12294eb11f2d3d3fd1adb20314ba89e94f44ed59"}, + {file = "coverage-7.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:db76a1bcb51f02b2007adacbed4c88b6dee75342c37b05d1822815eed19edee5"}, + {file = "coverage-7.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c02cfa6c36144ab334d556989406837336c1d05215a9bdf44c0bc1d1ac1cb637"}, + {file = "coverage-7.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:477c9430ad5d1b80b07f3c12f7120eef40bfbf849e9e7859e53b9c93b922d2af"}, + {file = "coverage-7.3.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ce2ee86ca75f9f96072295c5ebb4ef2a43cecf2870b0ca5e7a1cbdd929cf67e1"}, + {file = "coverage-7.3.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68d8a0426b49c053013e631c0cdc09b952d857efa8f68121746b339912d27a12"}, + {file = "coverage-7.3.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b3eb0c93e2ea6445b2173da48cb548364f8f65bf68f3d090404080d338e3a689"}, + {file = "coverage-7.3.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:90b6e2f0f66750c5a1178ffa9370dec6c508a8ca5265c42fbad3ccac210a7977"}, + {file = "coverage-7.3.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:96d7d761aea65b291a98c84e1250cd57b5b51726821a6f2f8df65db89363be51"}, + {file = "coverage-7.3.0-cp310-cp310-win32.whl", hash = "sha256:63c5b8ecbc3b3d5eb3a9d873dec60afc0cd5ff9d9f1c75981d8c31cfe4df8527"}, + {file = "coverage-7.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:97c44f4ee13bce914272589b6b41165bbb650e48fdb7bd5493a38bde8de730a1"}, + {file = "coverage-7.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:74c160285f2dfe0acf0f72d425f3e970b21b6de04157fc65adc9fd07ee44177f"}, + {file = "coverage-7.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b543302a3707245d454fc49b8ecd2c2d5982b50eb63f3535244fd79a4be0c99d"}, + {file = "coverage-7.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad0f87826c4ebd3ef484502e79b39614e9c03a5d1510cfb623f4a4a051edc6fd"}, + {file = "coverage-7.3.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:13c6cbbd5f31211d8fdb477f0f7b03438591bdd077054076eec362cf2207b4a7"}, + {file = "coverage-7.3.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fac440c43e9b479d1241fe9d768645e7ccec3fb65dc3a5f6e90675e75c3f3e3a"}, + {file = "coverage-7.3.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:3c9834d5e3df9d2aba0275c9f67989c590e05732439b3318fa37a725dff51e74"}, + {file = "coverage-7.3.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4c8e31cf29b60859876474034a83f59a14381af50cbe8a9dbaadbf70adc4b214"}, + {file = "coverage-7.3.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:7a9baf8e230f9621f8e1d00c580394a0aa328fdac0df2b3f8384387c44083c0f"}, + {file = "coverage-7.3.0-cp311-cp311-win32.whl", hash = "sha256:ccc51713b5581e12f93ccb9c5e39e8b5d4b16776d584c0f5e9e4e63381356482"}, + {file = "coverage-7.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:887665f00ea4e488501ba755a0e3c2cfd6278e846ada3185f42d391ef95e7e70"}, + {file = "coverage-7.3.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d000a739f9feed900381605a12a61f7aaced6beae832719ae0d15058a1e81c1b"}, + {file = "coverage-7.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:59777652e245bb1e300e620ce2bef0d341945842e4eb888c23a7f1d9e143c446"}, + {file = "coverage-7.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9737bc49a9255d78da085fa04f628a310c2332b187cd49b958b0e494c125071"}, + {file = "coverage-7.3.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5247bab12f84a1d608213b96b8af0cbb30d090d705b6663ad794c2f2a5e5b9fe"}, + {file = "coverage-7.3.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2ac9a1de294773b9fa77447ab7e529cf4fe3910f6a0832816e5f3d538cfea9a"}, + {file = "coverage-7.3.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:85b7335c22455ec12444cec0d600533a238d6439d8d709d545158c1208483873"}, + {file = "coverage-7.3.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:36ce5d43a072a036f287029a55b5c6a0e9bd73db58961a273b6dc11a2c6eb9c2"}, + {file = "coverage-7.3.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:211a4576e984f96d9fce61766ffaed0115d5dab1419e4f63d6992b480c2bd60b"}, + {file = "coverage-7.3.0-cp312-cp312-win32.whl", hash = "sha256:56afbf41fa4a7b27f6635bc4289050ac3ab7951b8a821bca46f5b024500e6321"}, + {file = "coverage-7.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:7f297e0c1ae55300ff688568b04ff26b01c13dfbf4c9d2b7d0cb688ac60df479"}, + {file = "coverage-7.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ac0dec90e7de0087d3d95fa0533e1d2d722dcc008bc7b60e1143402a04c117c1"}, + {file = "coverage-7.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:438856d3f8f1e27f8e79b5410ae56650732a0dcfa94e756df88c7e2d24851fcd"}, + {file = "coverage-7.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1084393c6bda8875c05e04fce5cfe1301a425f758eb012f010eab586f1f3905e"}, + {file = "coverage-7.3.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49ab200acf891e3dde19e5aa4b0f35d12d8b4bd805dc0be8792270c71bd56c54"}, + {file = "coverage-7.3.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a67e6bbe756ed458646e1ef2b0778591ed4d1fcd4b146fc3ba2feb1a7afd4254"}, + {file = "coverage-7.3.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8f39c49faf5344af36042b293ce05c0d9004270d811c7080610b3e713251c9b0"}, + {file = "coverage-7.3.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:7df91fb24c2edaabec4e0eee512ff3bc6ec20eb8dccac2e77001c1fe516c0c84"}, + {file = "coverage-7.3.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:34f9f0763d5fa3035a315b69b428fe9c34d4fc2f615262d6be3d3bf3882fb985"}, + {file = "coverage-7.3.0-cp38-cp38-win32.whl", hash = "sha256:bac329371d4c0d456e8d5f38a9b0816b446581b5f278474e416ea0c68c47dcd9"}, + {file = "coverage-7.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:b859128a093f135b556b4765658d5d2e758e1fae3e7cc2f8c10f26fe7005e543"}, + {file = "coverage-7.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fc0ed8d310afe013db1eedd37176d0839dc66c96bcfcce8f6607a73ffea2d6ba"}, + {file = "coverage-7.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61260ec93f99f2c2d93d264b564ba912bec502f679793c56f678ba5251f0393"}, + {file = "coverage-7.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:97af9554a799bd7c58c0179cc8dbf14aa7ab50e1fd5fa73f90b9b7215874ba28"}, + {file = "coverage-7.3.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3558e5b574d62f9c46b76120a5c7c16c4612dc2644c3d48a9f4064a705eaee95"}, + {file = "coverage-7.3.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:37d5576d35fcb765fca05654f66aa71e2808d4237d026e64ac8b397ffa66a56a"}, + {file = "coverage-7.3.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:07ea61bcb179f8f05ffd804d2732b09d23a1238642bf7e51dad62082b5019b34"}, + {file = "coverage-7.3.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:80501d1b2270d7e8daf1b64b895745c3e234289e00d5f0e30923e706f110334e"}, + {file = "coverage-7.3.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4eddd3153d02204f22aef0825409091a91bf2a20bce06fe0f638f5c19a85de54"}, + {file = "coverage-7.3.0-cp39-cp39-win32.whl", hash = "sha256:2d22172f938455c156e9af2612650f26cceea47dc86ca048fa4e0b2d21646ad3"}, + {file = "coverage-7.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:60f64e2007c9144375dd0f480a54d6070f00bb1a28f65c408370544091c9bc9e"}, + {file = "coverage-7.3.0-pp38.pp39.pp310-none-any.whl", hash = "sha256:5492a6ce3bdb15c6ad66cb68a0244854d9917478877a25671d70378bdc8562d0"}, + {file = "coverage-7.3.0.tar.gz", hash = "sha256:49dbb19cdcafc130f597d9e04a29d0a032ceedf729e41b181f51cd170e6ee865"}, ] [package.dependencies] @@ -487,43 +479,48 @@ toml = ["tomli"] [[package]] name = "cryptography" -version = "36.0.2" +version = "41.0.3" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "cryptography-36.0.2-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:4e2dddd38a5ba733be6a025a1475a9f45e4e41139d1321f412c6b360b19070b6"}, - {file = "cryptography-36.0.2-cp36-abi3-macosx_10_10_x86_64.whl", hash = "sha256:4881d09298cd0b669bb15b9cfe6166f16fc1277b4ed0d04a22f3d6430cb30f1d"}, - {file = "cryptography-36.0.2-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ea634401ca02367c1567f012317502ef3437522e2fc44a3ea1844de028fa4b84"}, - {file = "cryptography-36.0.2-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:7be666cc4599b415f320839e36367b273db8501127b38316f3b9f22f17a0b815"}, - {file = "cryptography-36.0.2-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8241cac0aae90b82d6b5c443b853723bcc66963970c67e56e71a2609dc4b5eaf"}, - {file = "cryptography-36.0.2-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b2d54e787a884ffc6e187262823b6feb06c338084bbe80d45166a1cb1c6c5bf"}, - {file = "cryptography-36.0.2-cp36-abi3-manylinux_2_24_x86_64.whl", hash = "sha256:c2c5250ff0d36fd58550252f54915776940e4e866f38f3a7866d92b32a654b86"}, - {file = "cryptography-36.0.2-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:ec6597aa85ce03f3e507566b8bcdf9da2227ec86c4266bd5e6ab4d9e0cc8dab2"}, - {file = "cryptography-36.0.2-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:ca9f686517ec2c4a4ce930207f75c00bf03d94e5063cbc00a1dc42531511b7eb"}, - {file = "cryptography-36.0.2-cp36-abi3-win32.whl", hash = "sha256:f64b232348ee82f13aac22856515ce0195837f6968aeaa94a3d0353ea2ec06a6"}, - {file = "cryptography-36.0.2-cp36-abi3-win_amd64.whl", hash = "sha256:53e0285b49fd0ab6e604f4c5d9c5ddd98de77018542e88366923f152dbeb3c29"}, - {file = "cryptography-36.0.2-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:32db5cc49c73f39aac27574522cecd0a4bb7384e71198bc65a0d23f901e89bb7"}, - {file = "cryptography-36.0.2-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b3d199647468d410994dbeb8cec5816fb74feb9368aedf300af709ef507e3e"}, - {file = "cryptography-36.0.2-pp37-pypy37_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:da73d095f8590ad437cd5e9faf6628a218aa7c387e1fdf67b888b47ba56a17f0"}, - {file = "cryptography-36.0.2-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:0a3bf09bb0b7a2c93ce7b98cb107e9170a90c51a0162a20af1c61c765b90e60b"}, - {file = "cryptography-36.0.2-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8897b7b7ec077c819187a123174b645eb680c13df68354ed99f9b40a50898f77"}, - {file = "cryptography-36.0.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82740818f2f240a5da8dfb8943b360e4f24022b093207160c77cadade47d7c85"}, - {file = "cryptography-36.0.2-pp38-pypy38_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:1f64a62b3b75e4005df19d3b5235abd43fa6358d5516cfc43d87aeba8d08dd51"}, - {file = "cryptography-36.0.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:e167b6b710c7f7bc54e67ef593f8731e1f45aa35f8a8a7b72d6e42ec76afd4b3"}, - {file = "cryptography-36.0.2.tar.gz", hash = "sha256:70f8f4f7bb2ac9f340655cbac89d68c527af5bb4387522a8413e841e3e6628c9"}, + {file = "cryptography-41.0.3-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:652627a055cb52a84f8c448185922241dd5217443ca194d5739b44612c5e6507"}, + {file = "cryptography-41.0.3-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:8f09daa483aedea50d249ef98ed500569841d6498aa9c9f4b0531b9964658922"}, + {file = "cryptography-41.0.3-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4fd871184321100fb400d759ad0cddddf284c4b696568204d281c902fc7b0d81"}, + {file = "cryptography-41.0.3-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:84537453d57f55a50a5b6835622ee405816999a7113267739a1b4581f83535bd"}, + {file = "cryptography-41.0.3-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:3fb248989b6363906827284cd20cca63bb1a757e0a2864d4c1682a985e3dca47"}, + {file = "cryptography-41.0.3-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:42cb413e01a5d36da9929baa9d70ca90d90b969269e5a12d39c1e0d475010116"}, + {file = "cryptography-41.0.3-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:aeb57c421b34af8f9fe830e1955bf493a86a7996cc1338fe41b30047d16e962c"}, + {file = "cryptography-41.0.3-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:6af1c6387c531cd364b72c28daa29232162010d952ceb7e5ca8e2827526aceae"}, + {file = "cryptography-41.0.3-cp37-abi3-win32.whl", hash = "sha256:0d09fb5356f975974dbcb595ad2d178305e5050656affb7890a1583f5e02a306"}, + {file = "cryptography-41.0.3-cp37-abi3-win_amd64.whl", hash = "sha256:a983e441a00a9d57a4d7c91b3116a37ae602907a7618b882c8013b5762e80574"}, + {file = "cryptography-41.0.3-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5259cb659aa43005eb55a0e4ff2c825ca111a0da1814202c64d28a985d33b087"}, + {file = "cryptography-41.0.3-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:67e120e9a577c64fe1f611e53b30b3e69744e5910ff3b6e97e935aeb96005858"}, + {file = "cryptography-41.0.3-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:7efe8041897fe7a50863e51b77789b657a133c75c3b094e51b5e4b5cec7bf906"}, + {file = "cryptography-41.0.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ce785cf81a7bdade534297ef9e490ddff800d956625020ab2ec2780a556c313e"}, + {file = "cryptography-41.0.3-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:57a51b89f954f216a81c9d057bf1a24e2f36e764a1ca9a501a6964eb4a6800dd"}, + {file = "cryptography-41.0.3-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:4c2f0d35703d61002a2bbdcf15548ebb701cfdd83cdc12471d2bae80878a4207"}, + {file = "cryptography-41.0.3-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:23c2d778cf829f7d0ae180600b17e9fceea3c2ef8b31a99e3c694cbbf3a24b84"}, + {file = "cryptography-41.0.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:95dd7f261bb76948b52a5330ba5202b91a26fbac13ad0e9fc8a3ac04752058c7"}, + {file = "cryptography-41.0.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:41d7aa7cdfded09b3d73a47f429c298e80796c8e825ddfadc84c8a7f12df212d"}, + {file = "cryptography-41.0.3-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:d0d651aa754ef58d75cec6edfbd21259d93810b73f6ec246436a21b7841908de"}, + {file = "cryptography-41.0.3-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:ab8de0d091acbf778f74286f4989cf3d1528336af1b59f3e5d2ebca8b5fe49e1"}, + {file = "cryptography-41.0.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a74fbcdb2a0d46fe00504f571a2a540532f4c188e6ccf26f1f178480117b33c4"}, + {file = "cryptography-41.0.3.tar.gz", hash = "sha256:6d192741113ef5e30d89dcb5b956ef4e1578f304708701b8b73d38e3e1461f34"}, ] [package.dependencies] cffi = ">=1.12" [package.extras] -docs = ["sphinx (>=1.6.5,!=1.8.0,!=3.1.0,!=3.1.1)", "sphinx-rtd-theme"] +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)"] -pep8test = ["black", "flake8", "flake8-import-order", "pep8-naming"] -sdist = ["setuptools-rust (>=0.11.4)"] +nox = ["nox"] +pep8test = ["black", "check-sdist", "mypy", "ruff"] +sdist = ["build"] ssh = ["bcrypt (>=3.1.5)"] -test = ["hypothesis (>=1.11.4,!=3.79.2)", "iso8601", "pretend", "pytest (>=6.2.0)", "pytest-cov", "pytest-subtests", "pytest-xdist", "pytz"] +test = ["pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] +test-randomorder = ["pytest-randomly"] [[package]] name = "distlib" @@ -577,13 +574,13 @@ tests = ["dj-database-url", "dj-email-url", "django-cache-url", "pytest"] [[package]] name = "exceptiongroup" -version = "1.1.2" +version = "1.1.3" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" files = [ - {file = "exceptiongroup-1.1.2-py3-none-any.whl", hash = "sha256:e346e69d186172ca7cf029c8c1d16235aa0e04035e5750b4b95039e65204328f"}, - {file = "exceptiongroup-1.1.2.tar.gz", hash = "sha256:12c3e887d6485d16943a309616de20ae5582633e0a2eda17f4e10fd61c1e8af5"}, + {file = "exceptiongroup-1.1.3-py3-none-any.whl", hash = "sha256:343280667a4585d195ca1cf9cef84a4e178c4b6cf2274caef9859782b567d5e3"}, + {file = "exceptiongroup-1.1.3.tar.gz", hash = "sha256:097acd85d473d75af5bb98e41b61ff7fe35efe6675e4f9370ec6ec5126d160e9"}, ] [package.extras] @@ -591,24 +588,22 @@ test = ["pytest (>=6)"] [[package]] name = "fastapi" -version = "0.83.0" +version = "0.101.1" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" optional = false -python-versions = ">=3.6.1" +python-versions = ">=3.7" files = [ - {file = "fastapi-0.83.0-py3-none-any.whl", hash = "sha256:694a2b6c2607a61029a4be1c6613f84d74019cb9f7a41c7a475dca8e715f9368"}, - {file = "fastapi-0.83.0.tar.gz", hash = "sha256:96eb692350fe13d7a9843c3c87a874f0d45102975257dd224903efd6c0fde3bd"}, + {file = "fastapi-0.101.1-py3-none-any.whl", hash = "sha256:aef5f8676eb1b8389952e1fe734abe20f04b71f6936afcc53b320ba79b686a4b"}, + {file = "fastapi-0.101.1.tar.gz", hash = "sha256:7b32000d14ca9992f7461117b81e4ef9ff0c07936af641b4fe40e67d5f9d63cb"}, ] [package.dependencies] -pydantic = ">=1.6.2,<1.7 || >1.7,<1.7.1 || >1.7.1,<1.7.2 || >1.7.2,<1.7.3 || >1.7.3,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0" -starlette = "0.19.1" +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.27.0,<0.28.0" +typing-extensions = ">=4.5.0" [package.extras] -all = ["email_validator (>=1.1.1,<2.0.0)", "itsdangerous (>=1.1.0,<3.0.0)", "jinja2 (>=2.11.2,<4.0.0)", "orjson (>=3.2.1,<4.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "pyyaml (>=5.3.1,<7.0.0)", "requests (>=2.24.0,<3.0.0)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,<6.0.0)", "uvicorn[standard] (>=0.12.0,<0.18.0)"] -dev = ["autoflake (>=1.4.0,<2.0.0)", "flake8 (>=3.8.3,<6.0.0)", "passlib[bcrypt] (>=1.7.2,<2.0.0)", "pre-commit (>=2.17.0,<3.0.0)", "python-jose[cryptography] (>=3.3.0,<4.0.0)", "uvicorn[standard] (>=0.12.0,<0.18.0)"] -doc = ["mdx-include (>=1.4.1,<2.0.0)", "mkdocs (>=1.1.2,<2.0.0)", "mkdocs-markdownextradata-plugin (>=0.1.7,<0.3.0)", "mkdocs-material (>=8.1.4,<9.0.0)", "pyyaml (>=5.3.1,<7.0.0)", "typer (>=0.4.1,<0.5.0)"] -test = ["anyio[trio] (>=3.2.1,<4.0.0)", "black (==22.3.0)", "databases[sqlite] (>=0.3.2,<0.6.0)", "email_validator (>=1.1.1,<2.0.0)", "flake8 (>=3.8.3,<6.0.0)", "flask (>=1.1.2,<3.0.0)", "httpx (>=0.14.0,<0.19.0)", "isort (>=5.0.6,<6.0.0)", "mypy (==0.910)", "orjson (>=3.2.1,<4.0.0)", "peewee (>=3.13.3,<4.0.0)", "pytest (>=6.2.4,<7.0.0)", "pytest-cov (>=2.12.0,<4.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "requests (>=2.24.0,<3.0.0)", "sqlalchemy (>=1.3.18,<1.5.0)", "types-dataclasses (==0.6.5)", "types-orjson (==3.6.2)", "types-ujson (==4.2.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,<6.0.0)"] +all = ["email-validator (>=2.0.0)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.5)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] [[package]] name = "filelock" @@ -627,30 +622,30 @@ testing = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "diff-cover (>=7.5)", "p [[package]] name = "h11" -version = "0.12.0" +version = "0.14.0" description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "h11-0.12.0-py3-none-any.whl", hash = "sha256:36a3cb8c0a032f56e2da7084577878a035d3b61d104230d4bd49c0c6b555a9c6"}, - {file = "h11-0.12.0.tar.gz", hash = "sha256:47222cb6067e4a307d535814917cd98fd0a57b6788ce715755fa2b6c28b56042"}, + {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, + {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, ] [[package]] name = "httpcore" -version = "0.15.0" +version = "0.17.3" description = "A minimal low-level HTTP client." optional = false python-versions = ">=3.7" files = [ - {file = "httpcore-0.15.0-py3-none-any.whl", hash = "sha256:1105b8b73c025f23ff7c36468e4432226cbb959176eab66864b8e31c4ee27fa6"}, - {file = "httpcore-0.15.0.tar.gz", hash = "sha256:18b68ab86a3ccf3e7dc0f43598eaddcf472b602aba29f9aa6ab85fe2ada3980b"}, + {file = "httpcore-0.17.3-py3-none-any.whl", hash = "sha256:c2789b767ddddfa2a5782e3199b2b7f6894540b17b16ec26b2c4d8e103510b87"}, + {file = "httpcore-0.17.3.tar.gz", hash = "sha256:a6f30213335e34c1ade7be6ec7c47f19f50c56db36abef1a9dfa3815b1cb3888"}, ] [package.dependencies] -anyio = "==3.*" +anyio = ">=3.0,<5.0" certifi = "*" -h11 = ">=0.11,<0.13" +h11 = ">=0.13,<0.15" sniffio = "==1.*" [package.extras] @@ -659,36 +654,36 @@ socks = ["socksio (==1.*)"] [[package]] name = "httpx" -version = "0.23.0" +version = "0.24.1" description = "The next generation HTTP client." optional = false python-versions = ">=3.7" files = [ - {file = "httpx-0.23.0-py3-none-any.whl", hash = "sha256:42974f577483e1e932c3cdc3cd2303e883cbfba17fe228b0f63589764d7b9c4b"}, - {file = "httpx-0.23.0.tar.gz", hash = "sha256:f28eac771ec9eb4866d3fb4ab65abd42d38c424739e80c08d8d20570de60b0ef"}, + {file = "httpx-0.24.1-py3-none-any.whl", hash = "sha256:06781eb9ac53cde990577af654bd990a4949de37a28bdb4a230d434f3a30b9bd"}, + {file = "httpx-0.24.1.tar.gz", hash = "sha256:5853a43053df830c20f8110c5e69fe44d035d850b2dfe795e196f00fdb774bdd"}, ] [package.dependencies] certifi = "*" -httpcore = ">=0.15.0,<0.16.0" -rfc3986 = {version = ">=1.3,<2", extras = ["idna2008"]} +httpcore = ">=0.15.0,<0.18.0" +idna = "*" sniffio = "*" [package.extras] brotli = ["brotli", "brotlicffi"] -cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<13)"] +cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] http2 = ["h2 (>=3,<5)"] socks = ["socksio (==1.*)"] [[package]] name = "identify" -version = "2.5.26" +version = "2.5.27" description = "File identification library for Python" optional = false python-versions = ">=3.8" files = [ - {file = "identify-2.5.26-py2.py3-none-any.whl", hash = "sha256:c22a8ead0d4ca11f1edd6c9418c3220669b3b7533ada0a0ffa6cc0ef85cf9b54"}, - {file = "identify-2.5.26.tar.gz", hash = "sha256:7243800bce2f58404ed41b7c002e53d4d22bcf3ae1b7900c2d7aefd95394bf7f"}, + {file = "identify-2.5.27-py2.py3-none-any.whl", hash = "sha256:fdb527b2dfe24602809b2201e033c2a113d7bdf716db3ca8e3243f735dcecaba"}, + {file = "identify-2.5.27.tar.gz", hash = "sha256:287b75b04a0e22d727bc9a41f0d4f3c1bcada97490fa6eabb5b28f0e9097e733"}, ] [package.extras] @@ -707,13 +702,13 @@ files = [ [[package]] name = "importlib-metadata" -version = "5.2.0" +version = "6.8.0" description = "Read metadata from Python packages" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "importlib_metadata-5.2.0-py3-none-any.whl", hash = "sha256:0eafa39ba42bf225fc00e67f701d71f85aead9f878569caf13c3724f704b970f"}, - {file = "importlib_metadata-5.2.0.tar.gz", hash = "sha256:404d48d62bba0b7a77ff9d405efd91501bef2e67ff4ace0bed40a0cf28c3c7cd"}, + {file = "importlib_metadata-6.8.0-py3-none-any.whl", hash = "sha256:3ebb78df84a805d7698245025b975d9d67053cd94c79245ba4b3eb694abe68bb"}, + {file = "importlib_metadata-6.8.0.tar.gz", hash = "sha256:dbace7892d8c0c4ac1ad096662232f831d4e64f4c4545bd53016a3e9d4654743"}, ] [package.dependencies] @@ -722,7 +717,7 @@ zipp = ">=0.5" [package.extras] docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] perf = ["ipython"] -testing = ["flake8 (<5)", "flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)"] +testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)", "pytest-ruff"] [[package]] name = "iniconfig" @@ -737,13 +732,13 @@ files = [ [[package]] name = "loguru" -version = "0.6.0" +version = "0.7.0" description = "Python logging made (stupidly) simple" optional = false python-versions = ">=3.5" files = [ - {file = "loguru-0.6.0-py3-none-any.whl", hash = "sha256:4e2414d534a2ab57573365b3e6d0234dfb1d84b68b7f3b948e6fb743860a77c3"}, - {file = "loguru-0.6.0.tar.gz", hash = "sha256:066bd06758d0a513e9836fd9c6b5a75bfb3fd36841f4b996bc60b547a309d41c"}, + {file = "loguru-0.7.0-py3-none-any.whl", hash = "sha256:b93aa30099fa6860d4727f1b81f8718e965bb96253fa190fab2077aaad6d15d3"}, + {file = "loguru-0.7.0.tar.gz", hash = "sha256:1612053ced6ae84d7959dd7d5e431a0532642237ec21f7fd83ac73fe539e03e1"}, ] [package.dependencies] @@ -751,7 +746,7 @@ colorama = {version = ">=0.3.4", markers = "sys_platform == \"win32\""} win32-setctime = {version = ">=1.0.0", markers = "sys_platform == \"win32\""} [package.extras] -dev = ["Sphinx (>=4.1.1)", "black (>=19.10b0)", "colorama (>=0.3.4)", "docutils (==0.16)", "flake8 (>=3.7.7)", "isort (>=5.1.1)", "pytest (>=4.6.2)", "pytest-cov (>=2.7.1)", "sphinx-autobuild (>=0.7.1)", "sphinx-rtd-theme (>=0.4.3)", "tox (>=3.9.0)"] +dev = ["Sphinx (==5.3.0)", "colorama (==0.4.5)", "colorama (==0.4.6)", "freezegun (==1.1.0)", "freezegun (==1.2.2)", "mypy (==v0.910)", "mypy (==v0.971)", "mypy (==v0.990)", "pre-commit (==3.2.1)", "pytest (==6.1.2)", "pytest (==7.2.1)", "pytest-cov (==2.12.1)", "pytest-cov (==4.0.0)", "pytest-mypy-plugins (==1.10.1)", "pytest-mypy-plugins (==1.9.3)", "sphinx-autobuild (==2021.3.14)", "sphinx-rtd-theme (==1.2.0)", "tox (==3.27.1)", "tox (==4.4.6)"] [[package]] name = "marshmallow" @@ -786,44 +781,48 @@ files = [ [[package]] name = "mypy" -version = "0.971" +version = "1.5.1" description = "Optional static typing for Python" optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" files = [ - {file = "mypy-0.971-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f2899a3cbd394da157194f913a931edfd4be5f274a88041c9dc2d9cdcb1c315c"}, - {file = "mypy-0.971-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:98e02d56ebe93981c41211c05adb630d1d26c14195d04d95e49cd97dbc046dc5"}, - {file = "mypy-0.971-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:19830b7dba7d5356d3e26e2427a2ec91c994cd92d983142cbd025ebe81d69cf3"}, - {file = "mypy-0.971-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:02ef476f6dcb86e6f502ae39a16b93285fef97e7f1ff22932b657d1ef1f28655"}, - {file = "mypy-0.971-cp310-cp310-win_amd64.whl", hash = "sha256:25c5750ba5609a0c7550b73a33deb314ecfb559c350bb050b655505e8aed4103"}, - {file = "mypy-0.971-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d3348e7eb2eea2472db611486846742d5d52d1290576de99d59edeb7cd4a42ca"}, - {file = "mypy-0.971-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3fa7a477b9900be9b7dd4bab30a12759e5abe9586574ceb944bc29cddf8f0417"}, - {file = "mypy-0.971-cp36-cp36m-win_amd64.whl", hash = "sha256:2ad53cf9c3adc43cf3bea0a7d01a2f2e86db9fe7596dfecb4496a5dda63cbb09"}, - {file = "mypy-0.971-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:855048b6feb6dfe09d3353466004490b1872887150c5bb5caad7838b57328cc8"}, - {file = "mypy-0.971-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:23488a14a83bca6e54402c2e6435467a4138785df93ec85aeff64c6170077fb0"}, - {file = "mypy-0.971-cp37-cp37m-win_amd64.whl", hash = "sha256:4b21e5b1a70dfb972490035128f305c39bc4bc253f34e96a4adf9127cf943eb2"}, - {file = "mypy-0.971-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:9796a2ba7b4b538649caa5cecd398d873f4022ed2333ffde58eaf604c4d2cb27"}, - {file = "mypy-0.971-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5a361d92635ad4ada1b1b2d3630fc2f53f2127d51cf2def9db83cba32e47c856"}, - {file = "mypy-0.971-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b793b899f7cf563b1e7044a5c97361196b938e92f0a4343a5d27966a53d2ec71"}, - {file = "mypy-0.971-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d1ea5d12c8e2d266b5fb8c7a5d2e9c0219fedfeb493b7ed60cd350322384ac27"}, - {file = "mypy-0.971-cp38-cp38-win_amd64.whl", hash = "sha256:23c7ff43fff4b0df93a186581885c8512bc50fc4d4910e0f838e35d6bb6b5e58"}, - {file = "mypy-0.971-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:1f7656b69974a6933e987ee8ffb951d836272d6c0f81d727f1d0e2696074d9e6"}, - {file = "mypy-0.971-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d2022bfadb7a5c2ef410d6a7c9763188afdb7f3533f22a0a32be10d571ee4bbe"}, - {file = "mypy-0.971-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ef943c72a786b0f8d90fd76e9b39ce81fb7171172daf84bf43eaf937e9f220a9"}, - {file = "mypy-0.971-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d744f72eb39f69312bc6c2abf8ff6656973120e2eb3f3ec4f758ed47e414a4bf"}, - {file = "mypy-0.971-cp39-cp39-win_amd64.whl", hash = "sha256:77a514ea15d3007d33a9e2157b0ba9c267496acf12a7f2b9b9f8446337aac5b0"}, - {file = "mypy-0.971-py3-none-any.whl", hash = "sha256:0d054ef16b071149917085f51f89555a576e2618d5d9dd70bd6eea6410af3ac9"}, - {file = "mypy-0.971.tar.gz", hash = "sha256:40b0f21484238269ae6a57200c807d80debc6459d444c0489a102d7c6a75fa56"}, + {file = "mypy-1.5.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f33592ddf9655a4894aef22d134de7393e95fcbdc2d15c1ab65828eee5c66c70"}, + {file = "mypy-1.5.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:258b22210a4a258ccd077426c7a181d789d1121aca6db73a83f79372f5569ae0"}, + {file = "mypy-1.5.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9ec1f695f0c25986e6f7f8778e5ce61659063268836a38c951200c57479cc12"}, + {file = "mypy-1.5.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:abed92d9c8f08643c7d831300b739562b0a6c9fcb028d211134fc9ab20ccad5d"}, + {file = "mypy-1.5.1-cp310-cp310-win_amd64.whl", hash = "sha256:a156e6390944c265eb56afa67c74c0636f10283429171018446b732f1a05af25"}, + {file = "mypy-1.5.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6ac9c21bfe7bc9f7f1b6fae441746e6a106e48fc9de530dea29e8cd37a2c0cc4"}, + {file = "mypy-1.5.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:51cb1323064b1099e177098cb939eab2da42fea5d818d40113957ec954fc85f4"}, + {file = "mypy-1.5.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:596fae69f2bfcb7305808c75c00f81fe2829b6236eadda536f00610ac5ec2243"}, + {file = "mypy-1.5.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:32cb59609b0534f0bd67faebb6e022fe534bdb0e2ecab4290d683d248be1b275"}, + {file = "mypy-1.5.1-cp311-cp311-win_amd64.whl", hash = "sha256:159aa9acb16086b79bbb0016145034a1a05360626046a929f84579ce1666b315"}, + {file = "mypy-1.5.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f6b0e77db9ff4fda74de7df13f30016a0a663928d669c9f2c057048ba44f09bb"}, + {file = "mypy-1.5.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:26f71b535dfc158a71264e6dc805a9f8d2e60b67215ca0bfa26e2e1aa4d4d373"}, + {file = "mypy-1.5.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2fc3a600f749b1008cc75e02b6fb3d4db8dbcca2d733030fe7a3b3502902f161"}, + {file = "mypy-1.5.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:26fb32e4d4afa205b24bf645eddfbb36a1e17e995c5c99d6d00edb24b693406a"}, + {file = "mypy-1.5.1-cp312-cp312-win_amd64.whl", hash = "sha256:82cb6193de9bbb3844bab4c7cf80e6227d5225cc7625b068a06d005d861ad5f1"}, + {file = "mypy-1.5.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4a465ea2ca12804d5b34bb056be3a29dc47aea5973b892d0417c6a10a40b2d65"}, + {file = "mypy-1.5.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9fece120dbb041771a63eb95e4896791386fe287fefb2837258925b8326d6160"}, + {file = "mypy-1.5.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d28ddc3e3dfeab553e743e532fb95b4e6afad51d4706dd22f28e1e5e664828d2"}, + {file = "mypy-1.5.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:57b10c56016adce71fba6bc6e9fd45d8083f74361f629390c556738565af8eeb"}, + {file = "mypy-1.5.1-cp38-cp38-win_amd64.whl", hash = "sha256:ff0cedc84184115202475bbb46dd99f8dcb87fe24d5d0ddfc0fe6b8575c88d2f"}, + {file = "mypy-1.5.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8f772942d372c8cbac575be99f9cc9d9fb3bd95c8bc2de6c01411e2c84ebca8a"}, + {file = "mypy-1.5.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5d627124700b92b6bbaa99f27cbe615c8ea7b3402960f6372ea7d65faf376c14"}, + {file = "mypy-1.5.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:361da43c4f5a96173220eb53340ace68cda81845cd88218f8862dfb0adc8cddb"}, + {file = "mypy-1.5.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:330857f9507c24de5c5724235e66858f8364a0693894342485e543f5b07c8693"}, + {file = "mypy-1.5.1-cp39-cp39-win_amd64.whl", hash = "sha256:c543214ffdd422623e9fedd0869166c2f16affe4ba37463975043ef7d2ea8770"}, + {file = "mypy-1.5.1-py3-none-any.whl", hash = "sha256:f757063a83970d67c444f6e01d9550a7402322af3557ce7630d3c957386fa8f5"}, + {file = "mypy-1.5.1.tar.gz", hash = "sha256:b031b9601f1060bf1281feab89697324726ba0c0bae9d7cd7ab4b690940f0b92"}, ] [package.dependencies] -mypy-extensions = ">=0.4.3" +mypy-extensions = ">=1.0.0" tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} -typing-extensions = ">=3.10" +typing-extensions = ">=4.1.0" [package.extras] dmypy = ["psutil (>=4.0)"] -python2 = ["typed-ast (>=1.4.0,<2)"] +install-types = ["pip"] reports = ["lxml"] [[package]] @@ -878,29 +877,29 @@ files = [ [[package]] name = "pathspec" -version = "0.11.1" +version = "0.11.2" description = "Utility library for gitignore style pattern matching of file paths." optional = false python-versions = ">=3.7" files = [ - {file = "pathspec-0.11.1-py3-none-any.whl", hash = "sha256:d8af70af76652554bd134c22b3e8a1cc46ed7d91edcdd721ef1a0c51a84a5293"}, - {file = "pathspec-0.11.1.tar.gz", hash = "sha256:2798de800fa92780e33acca925945e9a19a133b715067cf165b8866c15a31687"}, + {file = "pathspec-0.11.2-py3-none-any.whl", hash = "sha256:1d6ed233af05e679efb96b1851550ea95bbb64b7c490b0f5aa52996c11e92a20"}, + {file = "pathspec-0.11.2.tar.gz", hash = "sha256:e0d8d0ac2f12da61956eb2306b69f9469b42f4deb0f3cb6ed47b9cce9996ced3"}, ] [[package]] name = "platformdirs" -version = "3.9.1" +version = "3.10.0" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." optional = false python-versions = ">=3.7" files = [ - {file = "platformdirs-3.9.1-py3-none-any.whl", hash = "sha256:ad8291ae0ae5072f66c16945166cb11c63394c7a3ad1b1bc9828ca3162da8c2f"}, - {file = "platformdirs-3.9.1.tar.gz", hash = "sha256:1b42b450ad933e981d56e59f1b97495428c9bd60698baab9f3eb3d00d5822421"}, + {file = "platformdirs-3.10.0-py3-none-any.whl", hash = "sha256:d7c24979f292f916dc9cbf8648319032f551ea8c49a4c9bf2fb556a02070ec1d"}, + {file = "platformdirs-3.10.0.tar.gz", hash = "sha256:b45696dab2d7cc691a3226759c0d3b00c47c8b6e293d96f6436f733303f77f6d"}, ] [package.extras] -docs = ["furo (>=2023.5.20)", "proselint (>=0.13)", "sphinx (>=7.0.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.3.1)", "pytest-cov (>=4.1)", "pytest-mock (>=3.10)"] +docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.1)", "sphinx-autodoc-typehints (>=1.24)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)"] [[package]] name = "pluggy" @@ -937,73 +936,71 @@ virtualenv = ">=20.10.0" [[package]] name = "psycopg2-binary" -version = "2.9.6" +version = "2.9.7" description = "psycopg2 - Python-PostgreSQL Database Adapter" optional = true python-versions = ">=3.6" files = [ - {file = "psycopg2-binary-2.9.6.tar.gz", hash = "sha256:1f64dcfb8f6e0c014c7f55e51c9759f024f70ea572fbdef123f85318c297947c"}, - {file = "psycopg2_binary-2.9.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d26e0342183c762de3276cca7a530d574d4e25121ca7d6e4a98e4f05cb8e4df7"}, - {file = "psycopg2_binary-2.9.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c48d8f2db17f27d41fb0e2ecd703ea41984ee19362cbce52c097963b3a1b4365"}, - {file = "psycopg2_binary-2.9.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffe9dc0a884a8848075e576c1de0290d85a533a9f6e9c4e564f19adf8f6e54a7"}, - {file = "psycopg2_binary-2.9.6-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8a76e027f87753f9bd1ab5f7c9cb8c7628d1077ef927f5e2446477153a602f2c"}, - {file = "psycopg2_binary-2.9.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6460c7a99fc939b849431f1e73e013d54aa54293f30f1109019c56a0b2b2ec2f"}, - {file = "psycopg2_binary-2.9.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ae102a98c547ee2288637af07393dd33f440c25e5cd79556b04e3fca13325e5f"}, - {file = "psycopg2_binary-2.9.6-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:9972aad21f965599ed0106f65334230ce826e5ae69fda7cbd688d24fa922415e"}, - {file = "psycopg2_binary-2.9.6-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:7a40c00dbe17c0af5bdd55aafd6ff6679f94a9be9513a4c7e071baf3d7d22a70"}, - {file = "psycopg2_binary-2.9.6-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:cacbdc5839bdff804dfebc058fe25684cae322987f7a38b0168bc1b2df703fb1"}, - {file = "psycopg2_binary-2.9.6-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7f0438fa20fb6c7e202863e0d5ab02c246d35efb1d164e052f2f3bfe2b152bd0"}, - {file = "psycopg2_binary-2.9.6-cp310-cp310-win32.whl", hash = "sha256:b6c8288bb8a84b47e07013bb4850f50538aa913d487579e1921724631d02ea1b"}, - {file = "psycopg2_binary-2.9.6-cp310-cp310-win_amd64.whl", hash = "sha256:61b047a0537bbc3afae10f134dc6393823882eb263088c271331602b672e52e9"}, - {file = "psycopg2_binary-2.9.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:964b4dfb7c1c1965ac4c1978b0f755cc4bd698e8aa2b7667c575fb5f04ebe06b"}, - {file = "psycopg2_binary-2.9.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:afe64e9b8ea66866a771996f6ff14447e8082ea26e675a295ad3bdbffdd72afb"}, - {file = "psycopg2_binary-2.9.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:15e2ee79e7cf29582ef770de7dab3d286431b01c3bb598f8e05e09601b890081"}, - {file = "psycopg2_binary-2.9.6-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dfa74c903a3c1f0d9b1c7e7b53ed2d929a4910e272add6700c38f365a6002820"}, - {file = "psycopg2_binary-2.9.6-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b83456c2d4979e08ff56180a76429263ea254c3f6552cd14ada95cff1dec9bb8"}, - {file = "psycopg2_binary-2.9.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0645376d399bfd64da57148694d78e1f431b1e1ee1054872a5713125681cf1be"}, - {file = "psycopg2_binary-2.9.6-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e99e34c82309dd78959ba3c1590975b5d3c862d6f279f843d47d26ff89d7d7e1"}, - {file = "psycopg2_binary-2.9.6-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4ea29fc3ad9d91162c52b578f211ff1c931d8a38e1f58e684c45aa470adf19e2"}, - {file = "psycopg2_binary-2.9.6-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:4ac30da8b4f57187dbf449294d23b808f8f53cad6b1fc3623fa8a6c11d176dd0"}, - {file = "psycopg2_binary-2.9.6-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e78e6e2a00c223e164c417628572a90093c031ed724492c763721c2e0bc2a8df"}, - {file = "psycopg2_binary-2.9.6-cp311-cp311-win32.whl", hash = "sha256:1876843d8e31c89c399e31b97d4b9725a3575bb9c2af92038464231ec40f9edb"}, - {file = "psycopg2_binary-2.9.6-cp311-cp311-win_amd64.whl", hash = "sha256:b4b24f75d16a89cc6b4cdff0eb6a910a966ecd476d1e73f7ce5985ff1328e9a6"}, - {file = "psycopg2_binary-2.9.6-cp36-cp36m-win32.whl", hash = "sha256:498807b927ca2510baea1b05cc91d7da4718a0f53cb766c154c417a39f1820a0"}, - {file = "psycopg2_binary-2.9.6-cp36-cp36m-win_amd64.whl", hash = "sha256:0d236c2825fa656a2d98bbb0e52370a2e852e5a0ec45fc4f402977313329174d"}, - {file = "psycopg2_binary-2.9.6-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:34b9ccdf210cbbb1303c7c4db2905fa0319391bd5904d32689e6dd5c963d2ea8"}, - {file = "psycopg2_binary-2.9.6-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:84d2222e61f313c4848ff05353653bf5f5cf6ce34df540e4274516880d9c3763"}, - {file = "psycopg2_binary-2.9.6-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:30637a20623e2a2eacc420059be11527f4458ef54352d870b8181a4c3020ae6b"}, - {file = "psycopg2_binary-2.9.6-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8122cfc7cae0da9a3077216528b8bb3629c43b25053284cc868744bfe71eb141"}, - {file = "psycopg2_binary-2.9.6-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:38601cbbfe600362c43714482f43b7c110b20cb0f8172422c616b09b85a750c5"}, - {file = "psycopg2_binary-2.9.6-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c7e62ab8b332147a7593a385d4f368874d5fe4ad4e341770d4983442d89603e3"}, - {file = "psycopg2_binary-2.9.6-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2ab652e729ff4ad76d400df2624d223d6e265ef81bb8aa17fbd63607878ecbee"}, - {file = "psycopg2_binary-2.9.6-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:c83a74b68270028dc8ee74d38ecfaf9c90eed23c8959fca95bd703d25b82c88e"}, - {file = "psycopg2_binary-2.9.6-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d4e6036decf4b72d6425d5b29bbd3e8f0ff1059cda7ac7b96d6ac5ed34ffbacd"}, - {file = "psycopg2_binary-2.9.6-cp37-cp37m-win32.whl", hash = "sha256:a8c28fd40a4226b4a84bdf2d2b5b37d2c7bd49486b5adcc200e8c7ec991dfa7e"}, - {file = "psycopg2_binary-2.9.6-cp37-cp37m-win_amd64.whl", hash = "sha256:51537e3d299be0db9137b321dfb6a5022caaab275775680e0c3d281feefaca6b"}, - {file = "psycopg2_binary-2.9.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cf4499e0a83b7b7edcb8dabecbd8501d0d3a5ef66457200f77bde3d210d5debb"}, - {file = "psycopg2_binary-2.9.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7e13a5a2c01151f1208d5207e42f33ba86d561b7a89fca67c700b9486a06d0e2"}, - {file = "psycopg2_binary-2.9.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e0f754d27fddcfd74006455b6e04e6705d6c31a612ec69ddc040a5468e44b4e"}, - {file = "psycopg2_binary-2.9.6-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d57c3fd55d9058645d26ae37d76e61156a27722097229d32a9e73ed54819982a"}, - {file = "psycopg2_binary-2.9.6-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:71f14375d6f73b62800530b581aed3ada394039877818b2d5f7fc77e3bb6894d"}, - {file = "psycopg2_binary-2.9.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:441cc2f8869a4f0f4bb408475e5ae0ee1f3b55b33f350406150277f7f35384fc"}, - {file = "psycopg2_binary-2.9.6-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:65bee1e49fa6f9cf327ce0e01c4c10f39165ee76d35c846ade7cb0ec6683e303"}, - {file = "psycopg2_binary-2.9.6-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:af335bac6b666cc6aea16f11d486c3b794029d9df029967f9938a4bed59b6a19"}, - {file = "psycopg2_binary-2.9.6-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:cfec476887aa231b8548ece2e06d28edc87c1397ebd83922299af2e051cf2827"}, - {file = "psycopg2_binary-2.9.6-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:65c07febd1936d63bfde78948b76cd4c2a411572a44ac50719ead41947d0f26b"}, - {file = "psycopg2_binary-2.9.6-cp38-cp38-win32.whl", hash = "sha256:4dfb4be774c4436a4526d0c554af0cc2e02082c38303852a36f6456ece7b3503"}, - {file = "psycopg2_binary-2.9.6-cp38-cp38-win_amd64.whl", hash = "sha256:02c6e3cf3439e213e4ee930308dc122d6fb4d4bea9aef4a12535fbd605d1a2fe"}, - {file = "psycopg2_binary-2.9.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e9182eb20f41417ea1dd8e8f7888c4d7c6e805f8a7c98c1081778a3da2bee3e4"}, - {file = "psycopg2_binary-2.9.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8a6979cf527e2603d349a91060f428bcb135aea2be3201dff794813256c274f1"}, - {file = "psycopg2_binary-2.9.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8338a271cb71d8da40b023a35d9c1e919eba6cbd8fa20a54b748a332c355d896"}, - {file = "psycopg2_binary-2.9.6-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e3ed340d2b858d6e6fb5083f87c09996506af483227735de6964a6100b4e6a54"}, - {file = "psycopg2_binary-2.9.6-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f81e65376e52f03422e1fb475c9514185669943798ed019ac50410fb4c4df232"}, - {file = "psycopg2_binary-2.9.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfb13af3c5dd3a9588000910178de17010ebcccd37b4f9794b00595e3a8ddad3"}, - {file = "psycopg2_binary-2.9.6-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4c727b597c6444a16e9119386b59388f8a424223302d0c06c676ec8b4bc1f963"}, - {file = "psycopg2_binary-2.9.6-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:4d67fbdaf177da06374473ef6f7ed8cc0a9dc640b01abfe9e8a2ccb1b1402c1f"}, - {file = "psycopg2_binary-2.9.6-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:0892ef645c2fabb0c75ec32d79f4252542d0caec1d5d949630e7d242ca4681a3"}, - {file = "psycopg2_binary-2.9.6-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:02c0f3757a4300cf379eb49f543fb7ac527fb00144d39246ee40e1df684ab514"}, - {file = "psycopg2_binary-2.9.6-cp39-cp39-win32.whl", hash = "sha256:c3dba7dab16709a33a847e5cd756767271697041fbe3fe97c215b1fc1f5c9848"}, - {file = "psycopg2_binary-2.9.6-cp39-cp39-win_amd64.whl", hash = "sha256:f6a88f384335bb27812293fdb11ac6aee2ca3f51d3c7820fe03de0a304ab6249"}, + {file = "psycopg2-binary-2.9.7.tar.gz", hash = "sha256:1b918f64a51ffe19cd2e230b3240ba481330ce1d4b7875ae67305bd1d37b041c"}, + {file = "psycopg2_binary-2.9.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ea5f8ee87f1eddc818fc04649d952c526db4426d26bab16efbe5a0c52b27d6ab"}, + {file = "psycopg2_binary-2.9.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2993ccb2b7e80844d534e55e0f12534c2871952f78e0da33c35e648bf002bbff"}, + {file = "psycopg2_binary-2.9.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dbbc3c5d15ed76b0d9db7753c0db40899136ecfe97d50cbde918f630c5eb857a"}, + {file = "psycopg2_binary-2.9.7-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:692df8763b71d42eb8343f54091368f6f6c9cfc56dc391858cdb3c3ef1e3e584"}, + {file = "psycopg2_binary-2.9.7-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9dcfd5d37e027ec393a303cc0a216be564b96c80ba532f3d1e0d2b5e5e4b1e6e"}, + {file = "psycopg2_binary-2.9.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17cc17a70dfb295a240db7f65b6d8153c3d81efb145d76da1e4a096e9c5c0e63"}, + {file = "psycopg2_binary-2.9.7-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e5666632ba2b0d9757b38fc17337d84bdf932d38563c5234f5f8c54fd01349c9"}, + {file = "psycopg2_binary-2.9.7-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:7db7b9b701974c96a88997d458b38ccb110eba8f805d4b4f74944aac48639b42"}, + {file = "psycopg2_binary-2.9.7-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:c82986635a16fb1fa15cd5436035c88bc65c3d5ced1cfaac7f357ee9e9deddd4"}, + {file = "psycopg2_binary-2.9.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4fe13712357d802080cfccbf8c6266a3121dc0e27e2144819029095ccf708372"}, + {file = "psycopg2_binary-2.9.7-cp310-cp310-win32.whl", hash = "sha256:122641b7fab18ef76b18860dd0c772290566b6fb30cc08e923ad73d17461dc63"}, + {file = "psycopg2_binary-2.9.7-cp310-cp310-win_amd64.whl", hash = "sha256:f8651cf1f144f9ee0fa7d1a1df61a9184ab72962531ca99f077bbdcba3947c58"}, + {file = "psycopg2_binary-2.9.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4ecc15666f16f97709106d87284c136cdc82647e1c3f8392a672616aed3c7151"}, + {file = "psycopg2_binary-2.9.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3fbb1184c7e9d28d67671992970718c05af5f77fc88e26fd7136613c4ece1f89"}, + {file = "psycopg2_binary-2.9.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8a7968fd20bd550431837656872c19575b687f3f6f98120046228e451e4064df"}, + {file = "psycopg2_binary-2.9.7-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:094af2e77a1976efd4956a031028774b827029729725e136514aae3cdf49b87b"}, + {file = "psycopg2_binary-2.9.7-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:26484e913d472ecb6b45937ea55ce29c57c662066d222fb0fbdc1fab457f18c5"}, + {file = "psycopg2_binary-2.9.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f309b77a7c716e6ed9891b9b42953c3ff7d533dc548c1e33fddc73d2f5e21f9"}, + {file = "psycopg2_binary-2.9.7-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:6d92e139ca388ccfe8c04aacc163756e55ba4c623c6ba13d5d1595ed97523e4b"}, + {file = "psycopg2_binary-2.9.7-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:2df562bb2e4e00ee064779902d721223cfa9f8f58e7e52318c97d139cf7f012d"}, + {file = "psycopg2_binary-2.9.7-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:4eec5d36dbcfc076caab61a2114c12094c0b7027d57e9e4387b634e8ab36fd44"}, + {file = "psycopg2_binary-2.9.7-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1011eeb0c51e5b9ea1016f0f45fa23aca63966a4c0afcf0340ccabe85a9f65bd"}, + {file = "psycopg2_binary-2.9.7-cp311-cp311-win32.whl", hash = "sha256:ded8e15f7550db9e75c60b3d9fcbc7737fea258a0f10032cdb7edc26c2a671fd"}, + {file = "psycopg2_binary-2.9.7-cp311-cp311-win_amd64.whl", hash = "sha256:8a136c8aaf6615653450817a7abe0fc01e4ea720ae41dfb2823eccae4b9062a3"}, + {file = "psycopg2_binary-2.9.7-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2dec5a75a3a5d42b120e88e6ed3e3b37b46459202bb8e36cd67591b6e5feebc1"}, + {file = "psycopg2_binary-2.9.7-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc10da7e7df3380426521e8c1ed975d22df678639da2ed0ec3244c3dc2ab54c8"}, + {file = "psycopg2_binary-2.9.7-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee919b676da28f78f91b464fb3e12238bd7474483352a59c8a16c39dfc59f0c5"}, + {file = "psycopg2_binary-2.9.7-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eb1c0e682138f9067a58fc3c9a9bf1c83d8e08cfbee380d858e63196466d5c86"}, + {file = "psycopg2_binary-2.9.7-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00d8db270afb76f48a499f7bb8fa70297e66da67288471ca873db88382850bf4"}, + {file = "psycopg2_binary-2.9.7-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:9b0c2b466b2f4d89ccc33784c4ebb1627989bd84a39b79092e560e937a11d4ac"}, + {file = "psycopg2_binary-2.9.7-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:51d1b42d44f4ffb93188f9b39e6d1c82aa758fdb8d9de65e1ddfe7a7d250d7ad"}, + {file = "psycopg2_binary-2.9.7-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:11abdbfc6f7f7dea4a524b5f4117369b0d757725798f1593796be6ece20266cb"}, + {file = "psycopg2_binary-2.9.7-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:f02f4a72cc3ab2565c6d9720f0343cb840fb2dc01a2e9ecb8bc58ccf95dc5c06"}, + {file = "psycopg2_binary-2.9.7-cp37-cp37m-win32.whl", hash = "sha256:81d5dd2dd9ab78d31a451e357315f201d976c131ca7d43870a0e8063b6b7a1ec"}, + {file = "psycopg2_binary-2.9.7-cp37-cp37m-win_amd64.whl", hash = "sha256:62cb6de84d7767164a87ca97e22e5e0a134856ebcb08f21b621c6125baf61f16"}, + {file = "psycopg2_binary-2.9.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:59f7e9109a59dfa31efa022e94a244736ae401526682de504e87bd11ce870c22"}, + {file = "psycopg2_binary-2.9.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:95a7a747bdc3b010bb6a980f053233e7610276d55f3ca506afff4ad7749ab58a"}, + {file = "psycopg2_binary-2.9.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c721ee464e45ecf609ff8c0a555018764974114f671815a0a7152aedb9f3343"}, + {file = "psycopg2_binary-2.9.7-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f4f37bbc6588d402980ffbd1f3338c871368fb4b1cfa091debe13c68bb3852b3"}, + {file = "psycopg2_binary-2.9.7-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ac83ab05e25354dad798401babaa6daa9577462136ba215694865394840e31f8"}, + {file = "psycopg2_binary-2.9.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:024eaeb2a08c9a65cd5f94b31ace1ee3bb3f978cd4d079406aef85169ba01f08"}, + {file = "psycopg2_binary-2.9.7-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:1c31c2606ac500dbd26381145684d87730a2fac9a62ebcfbaa2b119f8d6c19f4"}, + {file = "psycopg2_binary-2.9.7-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:42a62ef0e5abb55bf6ffb050eb2b0fcd767261fa3faf943a4267539168807522"}, + {file = "psycopg2_binary-2.9.7-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:7952807f95c8eba6a8ccb14e00bf170bb700cafcec3924d565235dffc7dc4ae8"}, + {file = "psycopg2_binary-2.9.7-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e02bc4f2966475a7393bd0f098e1165d470d3fa816264054359ed4f10f6914ea"}, + {file = "psycopg2_binary-2.9.7-cp38-cp38-win32.whl", hash = "sha256:fdca0511458d26cf39b827a663d7d87db6f32b93efc22442a742035728603d5f"}, + {file = "psycopg2_binary-2.9.7-cp38-cp38-win_amd64.whl", hash = "sha256:d0b16e5bb0ab78583f0ed7ab16378a0f8a89a27256bb5560402749dbe8a164d7"}, + {file = "psycopg2_binary-2.9.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6822c9c63308d650db201ba22fe6648bd6786ca6d14fdaf273b17e15608d0852"}, + {file = "psycopg2_binary-2.9.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8f94cb12150d57ea433e3e02aabd072205648e86f1d5a0a692d60242f7809b15"}, + {file = "psycopg2_binary-2.9.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5ee89587696d808c9a00876065d725d4ae606f5f7853b961cdbc348b0f7c9a1"}, + {file = "psycopg2_binary-2.9.7-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ad5ec10b53cbb57e9a2e77b67e4e4368df56b54d6b00cc86398578f1c635f329"}, + {file = "psycopg2_binary-2.9.7-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:642df77484b2dcaf87d4237792246d8068653f9e0f5c025e2c692fc56b0dda70"}, + {file = "psycopg2_binary-2.9.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a6a8b575ac45af1eaccbbcdcf710ab984fd50af048fe130672377f78aaff6fc1"}, + {file = "psycopg2_binary-2.9.7-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f955aa50d7d5220fcb6e38f69ea126eafecd812d96aeed5d5f3597f33fad43bb"}, + {file = "psycopg2_binary-2.9.7-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:ad26d4eeaa0d722b25814cce97335ecf1b707630258f14ac4d2ed3d1d8415265"}, + {file = "psycopg2_binary-2.9.7-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:ced63c054bdaf0298f62681d5dcae3afe60cbae332390bfb1acf0e23dcd25fc8"}, + {file = "psycopg2_binary-2.9.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2b04da24cbde33292ad34a40db9832a80ad12de26486ffeda883413c9e1b1d5e"}, + {file = "psycopg2_binary-2.9.7-cp39-cp39-win32.whl", hash = "sha256:18f12632ab516c47c1ac4841a78fddea6508a8284c7cf0f292cb1a523f2e2379"}, + {file = "psycopg2_binary-2.9.7-cp39-cp39-win_amd64.whl", hash = "sha256:eb3b8d55924a6058a26db69fb1d3e7e32695ff8b491835ba9f479537e14dcf9f"}, ] [[package]] @@ -1146,19 +1143,20 @@ testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "no [[package]] name = "pytest-asyncio" -version = "0.19.0" +version = "0.21.1" description = "Pytest support for asyncio" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-asyncio-0.19.0.tar.gz", hash = "sha256:ac4ebf3b6207259750bc32f4c1d8fcd7e79739edbc67ad0c58dd150b1d072fed"}, - {file = "pytest_asyncio-0.19.0-py3-none-any.whl", hash = "sha256:7a97e37cfe1ed296e2e84941384bdd37c376453912d397ed39293e0916f521fa"}, + {file = "pytest-asyncio-0.21.1.tar.gz", hash = "sha256:40a7eae6dded22c7b604986855ea48400ab15b069ae38116e8c01238e9eeb64d"}, + {file = "pytest_asyncio-0.21.1-py3-none-any.whl", hash = "sha256:8666c1c8ac02631d7c51ba282e0c69a8a452b211ffedf2599099845da5c5c37b"}, ] [package.dependencies] -pytest = ">=6.1.0" +pytest = ">=7.0.0" [package.extras] +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]] @@ -1181,13 +1179,13 @@ testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtuale [[package]] name = "python-bitcoinlib" -version = "0.11.2" +version = "0.12.2" description = "The Swiss Army Knife of the Bitcoin protocol." optional = false python-versions = "*" files = [ - {file = "python-bitcoinlib-0.11.2.tar.gz", hash = "sha256:61ba514e0d232cc84741e49862dcedaf37199b40bba252a17edc654f63d13f39"}, - {file = "python_bitcoinlib-0.11.2-py3-none-any.whl", hash = "sha256:78bd4ee717fe805cd760dfdd08765e77b7c7dbef4627f8596285e84953756508"}, + {file = "python-bitcoinlib-0.12.2.tar.gz", hash = "sha256:c65ab61427c77c38d397bfc431f71d86fd355b453a536496ec3fcb41bd10087d"}, + {file = "python_bitcoinlib-0.12.2-py3-none-any.whl", hash = "sha256:2f29a9f475f21c12169b3a6cc8820f34f11362d7ff1200a5703dce3e4e903a44"}, ] [[package]] @@ -1291,23 +1289,6 @@ urllib3 = ">=1.21.1,<3" socks = ["PySocks (>=1.5.6,!=1.5.7)"] use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] -[[package]] -name = "rfc3986" -version = "1.5.0" -description = "Validating URI References per RFC 3986" -optional = false -python-versions = "*" -files = [ - {file = "rfc3986-1.5.0-py2.py3-none-any.whl", hash = "sha256:a86d6e1f5b1dc238b218b012df0aa79409667bb209e58da56d0b94704e712a97"}, - {file = "rfc3986-1.5.0.tar.gz", hash = "sha256:270aaf10d87d0d4e095063c65bf3ddbc6ee3d0b226328ce21e036f946e421835"}, -] - -[package.dependencies] -idna = {version = "*", optional = true, markers = "extra == \"idna2008\""} - -[package.extras] -idna2008 = ["idna"] - [[package]] name = "ruff" version = "0.0.284" @@ -1371,18 +1352,18 @@ cffi = ">=1.3.0" [[package]] name = "setuptools" -version = "65.7.0" +version = "68.1.2" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "setuptools-65.7.0-py3-none-any.whl", hash = "sha256:8ab4f1dbf2b4a65f7eec5ad0c620e84c34111a68d3349833494b9088212214dd"}, - {file = "setuptools-65.7.0.tar.gz", hash = "sha256:4d3c92fac8f1118bb77a22181355e29c239cabfe2b9effdaa665c66b711136d7"}, + {file = "setuptools-68.1.2-py3-none-any.whl", hash = "sha256:3d8083eed2d13afc9426f227b24fd1659489ec107c0e86cec2ffdde5c92e790b"}, + {file = "setuptools-68.1.2.tar.gz", hash = "sha256:3d4dfa6d95f1b101d695a6160a7626e15583af71a5f52176efa5d39a054d475d"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8 (<5)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5,<=7.1.2)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] [[package]] @@ -1485,13 +1466,13 @@ trio = ["trio (>=0.15)"] [[package]] name = "starlette" -version = "0.19.1" +version = "0.27.0" description = "The little ASGI library that shines." optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "starlette-0.19.1-py3-none-any.whl", hash = "sha256:5a60c5c2d051f3a8eb546136aa0c9399773a689595e099e0877704d5888279bf"}, - {file = "starlette-0.19.1.tar.gz", hash = "sha256:c6d21096774ecb9639acad41b86b7706e52ba3bf1dc13ea4ed9ad593d47e24c7"}, + {file = "starlette-0.27.0-py3-none-any.whl", hash = "sha256:918416370e846586541235ccd38a474c08b80443ed31c578a418e2209b3eef91"}, + {file = "starlette-0.27.0.tar.gz", hash = "sha256:6a6b0d042acb8d469a01eba54e9cda6cbd24ac602c4cd016723117d6a7e73b75"}, ] [package.dependencies] @@ -1499,7 +1480,7 @@ anyio = ">=3.4.0,<5" typing-extensions = {version = ">=3.10.0", markers = "python_version < \"3.10\""} [package.extras] -full = ["itsdangerous", "jinja2", "python-multipart", "pyyaml", "requests"] +full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart", "pyyaml"] [[package]] name = "tomli" @@ -1512,6 +1493,31 @@ files = [ {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, ] +[[package]] +name = "types-requests" +version = "2.31.0.2" +description = "Typing stubs for requests" +optional = false +python-versions = "*" +files = [ + {file = "types-requests-2.31.0.2.tar.gz", hash = "sha256:6aa3f7faf0ea52d728bb18c0a0d1522d9bfd8c72d26ff6f61bfc3d06a411cf40"}, + {file = "types_requests-2.31.0.2-py3-none-any.whl", hash = "sha256:56d181c85b5925cbc59f4489a57e72a8b2166f18273fd8ba7b6fe0c0b986f12a"}, +] + +[package.dependencies] +types-urllib3 = "*" + +[[package]] +name = "types-urllib3" +version = "1.26.25.14" +description = "Typing stubs for urllib3" +optional = false +python-versions = "*" +files = [ + {file = "types-urllib3-1.26.25.14.tar.gz", hash = "sha256:229b7f577c951b8c1b92c1bc2b2fdb0b49847bd2af6d1cc2a2e3dd340f3bda8f"}, + {file = "types_urllib3-1.26.25.14-py3-none-any.whl", hash = "sha256:9683bbb7fb72e32bfe9d2be6e04875fbe1b3eeec3cbb4ea231435aa7fd6b4f0e"}, +] + [[package]] name = "typing-extensions" version = "4.7.1" @@ -1560,13 +1566,13 @@ standard = ["colorama (>=0.4)", "httptools (>=0.4.0)", "python-dotenv (>=0.13)", [[package]] name = "virtualenv" -version = "20.24.2" +version = "20.24.3" description = "Virtual Python Environment builder" optional = false python-versions = ">=3.7" files = [ - {file = "virtualenv-20.24.2-py3-none-any.whl", hash = "sha256:43a3052be36080548bdee0b42919c88072037d50d56c28bd3f853cbe92b953ff"}, - {file = "virtualenv-20.24.2.tar.gz", hash = "sha256:fd8a78f46f6b99a67b7ec5cf73f92357891a7b3a40fd97637c27f854aae3b9e0"}, + {file = "virtualenv-20.24.3-py3-none-any.whl", hash = "sha256:95a6e9398b4967fbcb5fef2acec5efaf9aa4972049d9ae41f95e0972a683fd02"}, + {file = "virtualenv-20.24.3.tar.gz", hash = "sha256:e5c3b4ce817b0b328af041506a2a299418c98747c4b1e68cb7527e74ced23efc"}, ] [package.dependencies] @@ -1580,33 +1586,33 @@ test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess [[package]] name = "websocket-client" -version = "1.6.1" +version = "1.6.2" description = "WebSocket client for Python with low level API options" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "websocket-client-1.6.1.tar.gz", hash = "sha256:c951af98631d24f8df89ab1019fc365f2227c0892f12fd150e935607c79dd0dd"}, - {file = "websocket_client-1.6.1-py3-none-any.whl", hash = "sha256:f1f9f2ad5291f0225a49efad77abf9e700b6fef553900623060dad6e26503b9d"}, + {file = "websocket-client-1.6.2.tar.gz", hash = "sha256:53e95c826bf800c4c465f50093a8c4ff091c7327023b10bfaff40cf1ef170eaa"}, + {file = "websocket_client-1.6.2-py3-none-any.whl", hash = "sha256:ce54f419dfae71f4bdba69ebe65bf7f0a93fe71bc009ad3a010aacc3eebad537"}, ] [package.extras] -docs = ["Sphinx (>=3.4)", "sphinx-rtd-theme (>=0.5)"] +docs = ["Sphinx (>=6.0)", "sphinx-rtd-theme (>=1.1.0)"] optional = ["python-socks", "wsaccel"] test = ["websockets"] [[package]] name = "wheel" -version = "0.38.4" +version = "0.41.2" description = "A built-package format for Python" optional = false python-versions = ">=3.7" files = [ - {file = "wheel-0.38.4-py3-none-any.whl", hash = "sha256:b60533f3f5d530e971d6737ca6d58681ee434818fab630c83a734bb10c083ce8"}, - {file = "wheel-0.38.4.tar.gz", hash = "sha256:965f5259b566725405b05e7cf774052044b1ed30119b5d586b2703aafe8719ac"}, + {file = "wheel-0.41.2-py3-none-any.whl", hash = "sha256:75909db2664838d015e3d9139004ee16711748a52c8f336b52882266540215d8"}, + {file = "wheel-0.41.2.tar.gz", hash = "sha256:0c5ac5ff2afb79ac23ab82bab027a0be7b5dbcf2e54dc50efe4bf507de1f7985"}, ] [package.extras] -test = ["pytest (>=3.0.0)"] +test = ["pytest (>=6.0.0)", "setuptools (>=65)"] [[package]] name = "win32-setctime" @@ -1643,4 +1649,4 @@ pgsql = ["psycopg2-binary"] [metadata] lock-version = "2.0" python-versions = "^3.8.1" -content-hash = "83e8f09ebad4bca75c90591fbe0c50d0acf9d19edf6e30437e91fded95cd88c4" +content-hash = "b801dad77ac4c6b9aca8f25c4fe4d8bab9cb998a2e12d91d9bbf69cb66bb3085" diff --git a/pyproject.toml b/pyproject.toml index e3a58473..f5e34b2c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,28 +9,28 @@ license = "MIT" python = "^3.8.1" requests = "^2.27.1" SQLAlchemy = "^1.3.24" -click = "^8.0.4" +click = "^8.1.7" pydantic = "^1.10.2" bech32 = "^1.2.0" -fastapi = "^0.83.0" +fastapi = "^0.101.1" environs = "^9.5.0" uvicorn = "^0.18.3" -loguru = "^0.6.0" +loguru = "^0.7.0" ecdsa = "^0.18.0" bitstring = "^3.1.9" secp256k1 = "^0.14.0" sqlalchemy-aio = "^0.17.0" -python-bitcoinlib = "0.11.2" -h11 = "^0.12.0" +python-bitcoinlib = "^0.12.2" +h11 = "^0.14.0" PySocks = "^1.7.1" -cryptography = "^36.0.2" +cryptography = "^41.0.3" websocket-client = "^1.3.3" pycryptodomex = "^3.16.0" -setuptools = "^65.6.3" -wheel = "^0.38.4" -importlib-metadata = "^5.2.0" -psycopg2-binary = {version = "^2.9.5", optional = true } -httpx = "0.23.0" +setuptools = "^68.1.2" +wheel = "^0.41.1" +importlib-metadata = "^6.8.0" +psycopg2-binary = { version = "^2.9.7", optional = true } +httpx = "^0.24.1" bip32 = "^3.4" mnemonic = "^0.20" @@ -38,13 +38,14 @@ mnemonic = "^0.20" pgsql = ["psycopg2-binary"] [tool.poetry.group.dev.dependencies] -mypy = "^0.971" -pytest-asyncio = "^0.19.0" +mypy = "^1.5.1" +black = "^23.7.0" +pytest-asyncio = "^0.21.1" pytest-cov = "^4.0.0" pytest = "^7.4.0" -pre-commit = "^3.3.3" ruff = "^0.0.284" -black = "^23.7.0" +pre-commit = "^3.3.3" +types-requests = "^2.31.0.2" [build-system] requires = ["poetry-core>=1.0.0"] diff --git a/requirements.txt b/requirements.txt index 96271c72..f86f9607 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,51 +1,50 @@ -anyio==3.7.1 ; python_version >= "3.7" and python_version < "4.0" -asn1crypto==1.5.1 ; python_version >= "3.7" and python_version < "4.0" -attrs==23.1.0 ; python_version >= "3.7" and python_version < "4.0" -base58==2.1.1 ; python_version >= "3.7" and python_version < "4.0" -bech32==1.2.0 ; python_version >= "3.7" and python_version < "4.0" -bip32==3.4 ; python_version >= "3.7" and python_version < "4.0" -bitstring==3.1.9 ; python_version >= "3.7" and python_version < "4.0" -certifi==2023.5.7 ; python_version >= "3.7" and python_version < "4.0" -cffi==1.15.1 ; python_version >= "3.7" and python_version < "4.0" -charset-normalizer==3.2.0 ; python_version >= "3.7" and python_version < "4.0" -click==8.1.5 ; python_version >= "3.7" and python_version < "4.0" -coincurve==18.0.0 ; python_version >= "3.7" and python_version < "4.0" -colorama==0.4.6 ; python_version >= "3.7" and python_version < "4.0" and platform_system == "Windows" or python_version >= "3.7" and python_version < "4.0" and sys_platform == "win32" -cryptography==36.0.2 ; python_version >= "3.7" and python_version < "4.0" -ecdsa==0.18.0 ; python_version >= "3.7" and python_version < "4.0" -environs==9.5.0 ; python_version >= "3.7" and python_version < "4.0" -exceptiongroup==1.1.2 ; python_version >= "3.7" and python_version < "3.11" -fastapi==0.83.0 ; python_version >= "3.7" and python_version < "4.0" -h11==0.12.0 ; python_version >= "3.7" and python_version < "4.0" -httpcore==0.15.0 ; python_version >= "3.7" and python_version < "4.0" -httpx==0.23.0 ; python_version >= "3.7" and python_version < "4.0" -idna==3.4 ; python_version >= "3.7" and python_version < "4.0" -importlib-metadata==5.2.0 ; python_version >= "3.7" and python_version < "4.0" -loguru==0.6.0 ; python_version >= "3.7" and python_version < "4.0" -marshmallow==3.19.0 ; python_version >= "3.7" and python_version < "4.0" -mnemonic==0.20 ; python_version >= "3.7" and python_version < "4.0" -outcome==1.2.0 ; python_version >= "3.7" and python_version < "4.0" -packaging==23.1 ; python_version >= "3.7" and python_version < "4.0" -pycparser==2.21 ; python_version >= "3.7" and python_version < "4.0" -pycryptodomex==3.18.0 ; python_version >= "3.7" and python_version < "4.0" -pydantic==1.10.11 ; python_version >= "3.7" and python_version < "4.0" -pysocks==1.7.1 ; python_version >= "3.7" and python_version < "4.0" -python-bitcoinlib==0.11.2 ; python_version >= "3.7" and python_version < "4.0" -python-dotenv==0.21.1 ; python_version >= "3.7" and python_version < "4.0" -represent==1.6.0.post0 ; python_version >= "3.7" and python_version < "4.0" -requests==2.31.0 ; python_version >= "3.7" and python_version < "4.0" -rfc3986[idna2008]==1.5.0 ; python_version >= "3.7" and python_version < "4.0" -secp256k1==0.14.0 ; python_version >= "3.7" and python_version < "4.0" -setuptools==65.7.0 ; python_version >= "3.7" and python_version < "4.0" -six==1.16.0 ; python_version >= "3.7" and python_version < "4.0" -sniffio==1.3.0 ; python_version >= "3.7" and python_version < "4.0" -sqlalchemy-aio==0.17.0 ; python_version >= "3.7" and python_version < "4.0" -sqlalchemy==1.3.24 ; python_version >= "3.7" and python_version < "4.0" -starlette==0.19.1 ; python_version >= "3.7" and python_version < "4.0" -typing-extensions==4.7.1 ; python_version >= "3.7" and python_version < "4.0" -urllib3==2.0.3 ; python_version >= "3.7" and python_version < "4.0" -uvicorn==0.18.3 ; python_version >= "3.7" and python_version < "4.0" -websocket-client==1.6.1 ; python_version >= "3.7" and python_version < "4.0" -wheel==0.38.4 ; python_version >= "3.7" and python_version < "4.0" -win32-setctime==1.1.0 ; python_version >= "3.7" and python_version < "4.0" and sys_platform == "win32" -zipp==3.15.0 ; python_version >= "3.7" and python_version < "4.0" +anyio==3.7.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +asn1crypto==1.5.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +attrs==23.1.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +base58==2.1.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +bech32==1.2.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +bip32==3.4 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +bitstring==3.1.9 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +certifi==2023.7.22 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +cffi==1.15.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +charset-normalizer==3.2.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +click==8.1.7 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +coincurve==18.0.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +colorama==0.4.6 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" and (platform_system == "Windows" or sys_platform == "win32") +cryptography==41.0.3 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +ecdsa==0.18.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +environs==9.5.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +exceptiongroup==1.1.3 ; python_full_version >= "3.8.1" and python_version < "3.11" +fastapi==0.101.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +h11==0.14.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +httpcore==0.17.3 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +httpx==0.24.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +idna==3.4 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +importlib-metadata==6.8.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +loguru==0.7.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +marshmallow==3.20.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +mnemonic==0.20 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +outcome==1.2.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +packaging==23.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +pycparser==2.21 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +pycryptodomex==3.18.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +pydantic==1.10.12 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +pysocks==1.7.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +python-bitcoinlib==0.12.2 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +python-dotenv==1.0.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +represent==1.6.0.post0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +requests==2.31.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +secp256k1==0.14.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +setuptools==68.1.2 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +six==1.16.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +sniffio==1.3.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +sqlalchemy-aio==0.17.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +sqlalchemy==1.3.24 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +starlette==0.27.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +typing-extensions==4.7.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +urllib3==2.0.4 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +uvicorn==0.18.3 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +websocket-client==1.6.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +wheel==0.41.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +win32-setctime==1.1.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" and sys_platform == "win32" +zipp==3.16.2 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" diff --git a/tests/test_wallet.py b/tests/test_wallet.py index c5bd9601..9396ca52 100644 --- a/tests/test_wallet.py +++ b/tests/test_wallet.py @@ -244,7 +244,9 @@ async def test_duplicate_proofs_double_spent(wallet1: Wallet): @pytest.mark.asyncio async def test_send_and_redeem(wallet1: Wallet, wallet2: Wallet): await wallet1.mint(64) - _, spendable_proofs = await wallet1.split_to_send(wallet1.proofs, 32, set_reserved=True) # type: ignore + _, spendable_proofs = await wallet1.split_to_send( + wallet1.proofs, 32, set_reserved=True + ) await wallet2.redeem(spendable_proofs) assert wallet2.balance == 32 From f5516241321c02157b8b9619cbdbc90c8865b2fe Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Fri, 25 Aug 2023 23:50:16 +0200 Subject: [PATCH 6/9] [Wallet] Refactor `restore_promises_from_to` (#307) * refactor restore_promises_from_to * fix mypy * black * fix tests --- cashu/wallet/api/router.py | 8 +++---- cashu/wallet/wallet.py | 46 +++++++++++++++++++++++++++++--------- tests/test_wallet.py | 16 ++++++------- 3 files changed, 48 insertions(+), 22 deletions(-) diff --git a/cashu/wallet/api/router.py b/cashu/wallet/api/router.py index 0b96fa81..63820b9e 100644 --- a/cashu/wallet/api/router.py +++ b/cashu/wallet/api/router.py @@ -282,9 +282,9 @@ async def burn( wallet = await mint_wallet(mint) if not (all or token or force or delete) or (token and all): raise Exception( - "enter a token or use --all to burn all pending tokens, --force to check" - " all tokensor --delete with send ID to force-delete pending token from" - " list if mint is unavailable.", + "enter a token or use --all to burn all pending tokens, --force to" + " check all tokensor --delete with send ID to force-delete pending" + " token from list if mint is unavailable.", ) if all: # check only those who are flagged as reserved @@ -414,7 +414,7 @@ async def restore( if to < 0: raise Exception("Counter must be positive") await wallet.load_mint() - await wallet.restore_promises(0, to) + await wallet.restore_promises_from_to(0, to) await wallet.invalidate(wallet.proofs) wallet.status() return RestoreResponse(balance=wallet.available_balance) diff --git a/cashu/wallet/wallet.py b/cashu/wallet/wallet.py index 8926ffa7..69a40b50 100644 --- a/cashu/wallet/wallet.py +++ b/cashu/wallet/wallet.py @@ -1655,7 +1655,7 @@ async def restore_wallet_from_mnemonic( n_last_restored_proofs = 0 while stop_counter < to: print(f"Restoring token {i} to {i + batch}...") - restored_proofs = await self.restore_promises(i, i + batch - 1) + restored_proofs = await self.restore_promises_from_to(i, i + batch - 1) if len(restored_proofs) == 0: stop_counter += 1 spendable_proofs = await self.invalidate(restored_proofs) @@ -1679,7 +1679,9 @@ async def restore_wallet_from_mnemonic( print("No tokens restored.") return - async def restore_promises(self, from_counter: int, to_counter: int) -> List[Proof]: + async def restore_promises_from_to( + self, from_counter: int, to_counter: int + ) -> List[Proof]: """Restores promises from a given range of counters. This is for restoring a wallet from a mnemonic. Args: @@ -1698,14 +1700,42 @@ async def restore_promises(self, from_counter: int, to_counter: int) -> List[Pro # we generate outptus from deterministic secrets and rs regenerated_outputs, _ = self._construct_outputs(amounts_dummy, secrets, rs) # we ask the mint to reissue the promises - # restored_outputs is there so we can match the promises to the secrets and rs - restored_outputs, restored_promises = await super().restore_promises( - regenerated_outputs + proofs = await self.restore_promises( + outputs=regenerated_outputs, + secrets=secrets, + rs=rs, + derivation_paths=derivation_paths, + ) + + await set_secret_derivation( + db=self.db, keyset_id=self.keyset_id, counter=to_counter + 1 ) + return proofs + + async def restore_promises( + self, + outputs: List[BlindedMessage], + secrets: List[str], + rs: List[PrivateKey], + derivation_paths: List[str], + ) -> List[Proof]: + """Restores proofs from a list of outputs, secrets, rs and derivation paths. + + Args: + outputs (List[BlindedMessage]): Outputs for which we request promises + secrets (List[str]): Secrets generated for the outputs + rs (List[PrivateKey]): Random blinding factors generated for the outputs + derivation_paths (List[str]): Derivation paths for the secrets + + Returns: + List[Proof]: List of restored proofs + """ + # restored_outputs is there so we can match the promises to the secrets and rs + restored_outputs, restored_promises = await super().restore_promises(outputs) # now we need to filter out the secrets and rs that had a match matching_indices = [ idx - for idx, val in enumerate(regenerated_outputs) + for idx, val in enumerate(outputs) if val.B_ in [o.B_ for o in restored_outputs] ] secrets = [secrets[i] for i in matching_indices] @@ -1721,8 +1751,4 @@ async def restore_promises(self, from_counter: int, to_counter: int) -> List[Pro for proof in proofs: if proof.secret not in [p.secret for p in self.proofs]: self.proofs.append(proof) - - await set_secret_derivation( - db=self.db, keyset_id=self.keyset_id, counter=to_counter + 1 - ) return proofs diff --git a/tests/test_wallet.py b/tests/test_wallet.py index 9396ca52..f4ec78b6 100644 --- a/tests/test_wallet.py +++ b/tests/test_wallet.py @@ -387,7 +387,7 @@ async def test_restore_wallet_after_mint(wallet3: Wallet): await wallet3.load_proofs() wallet3.proofs = [] assert wallet3.balance == 0 - await wallet3.restore_promises(0, 20) + await wallet3.restore_promises_from_to(0, 20) assert wallet3.balance == 64 @@ -419,7 +419,7 @@ async def test_restore_wallet_after_split_to_send(wallet3: Wallet): await wallet3.load_proofs() wallet3.proofs = [] assert wallet3.balance == 0 - await wallet3.restore_promises(0, 100) + await wallet3.restore_promises_from_to(0, 100) assert wallet3.balance == 64 * 2 await wallet3.invalidate(wallet3.proofs) assert wallet3.balance == 64 @@ -443,7 +443,7 @@ async def test_restore_wallet_after_send_and_receive(wallet3: Wallet, wallet2: W await wallet3.load_proofs(reload=True) assert wallet3.proofs == [] assert wallet3.balance == 0 - await wallet3.restore_promises(0, 100) + await wallet3.restore_promises_from_to(0, 100) assert wallet3.balance == 64 + 2 * 32 await wallet3.invalidate(wallet3.proofs) assert wallet3.balance == 32 @@ -482,7 +482,7 @@ async def test_restore_wallet_after_send_and_self_receive(wallet3: Wallet): await wallet3.load_proofs(reload=True) assert wallet3.proofs == [] assert wallet3.balance == 0 - await wallet3.restore_promises(0, 100) + await wallet3.restore_promises_from_to(0, 100) assert wallet3.balance == 64 + 2 * 32 + 32 await wallet3.invalidate(wallet3.proofs) assert wallet3.balance == 64 @@ -512,7 +512,7 @@ async def test_restore_wallet_after_send_twice( await wallet3.load_proofs(reload=True) assert wallet3.proofs == [] assert wallet3.balance == 0 - await wallet3.restore_promises(0, 10) + await wallet3.restore_promises_from_to(0, 10) box.add(wallet3.proofs) assert wallet3.balance == 5 await wallet3.invalidate(wallet3.proofs) @@ -532,7 +532,7 @@ async def test_restore_wallet_after_send_twice( await wallet3.load_proofs(reload=True) assert wallet3.proofs == [] assert wallet3.balance == 0 - await wallet3.restore_promises(0, 15) + await wallet3.restore_promises_from_to(0, 15) box.add(wallet3.proofs) assert wallet3.balance == 7 await wallet3.invalidate(wallet3.proofs) @@ -565,7 +565,7 @@ async def test_restore_wallet_after_send_and_self_receive_nonquadratic_value( await wallet3.load_proofs(reload=True) assert wallet3.proofs == [] assert wallet3.balance == 0 - await wallet3.restore_promises(0, 20) + await wallet3.restore_promises_from_to(0, 20) box.add(wallet3.proofs) assert wallet3.balance == 138 await wallet3.invalidate(wallet3.proofs) @@ -583,7 +583,7 @@ async def test_restore_wallet_after_send_and_self_receive_nonquadratic_value( await wallet3.load_proofs(reload=True) assert wallet3.proofs == [] assert wallet3.balance == 0 - await wallet3.restore_promises(0, 50) + await wallet3.restore_promises_from_to(0, 50) assert wallet3.balance == 182 await wallet3.invalidate(wallet3.proofs) assert wallet3.balance == 64 From 87c0adc60d66357d324b257bc2f7a336e8a102c3 Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Fri, 25 Aug 2023 23:51:20 +0200 Subject: [PATCH 7/9] update requirements.txt (#308) --- requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/requirements.txt b/requirements.txt index f86f9607..d13ce215 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,7 +10,7 @@ cffi==1.15.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" charset-normalizer==3.2.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" click==8.1.7 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" coincurve==18.0.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" -colorama==0.4.6 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" and (platform_system == "Windows" or sys_platform == "win32") +colorama==0.4.6 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" and platform_system == "Windows" or python_full_version >= "3.8.1" and python_full_version < "4.0.0" and sys_platform == "win32" cryptography==41.0.3 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" ecdsa==0.18.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" environs==9.5.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" @@ -44,7 +44,7 @@ starlette==0.27.0 ; python_full_version >= "3.8.1" and python_full_version < "4. typing-extensions==4.7.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" urllib3==2.0.4 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" uvicorn==0.18.3 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" -websocket-client==1.6.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" -wheel==0.41.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +websocket-client==1.6.2 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" +wheel==0.41.2 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" win32-setctime==1.1.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" and sys_platform == "win32" zipp==3.16.2 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" From 75e8428af7af4f10ec01e4a124ff787d6e2f612b Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Fri, 8 Sep 2023 15:21:14 +0200 Subject: [PATCH 8/9] Mint/add_cors_to_error_response (#312) * add cors to error response and log validation errors * shorten hash for invoices to avoid base64 escape characters --- cashu/core/crypto/keys.py | 2 +- cashu/mint/app.py | 36 ++++++++++++++++++++++++++++++++++-- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/cashu/core/crypto/keys.py b/cashu/core/crypto/keys.py index 9993a91b..fcf8c9f0 100644 --- a/cashu/core/crypto/keys.py +++ b/cashu/core/crypto/keys.py @@ -58,5 +58,5 @@ def derive_keyset_id(keys: Dict[int, PublicKey]): def random_hash() -> str: """Returns a base64-urlsafe encoded random hash.""" return base64.urlsafe_b64encode( - bytes([random.getrandbits(8) for i in range(32)]) + bytes([random.getrandbits(8) for i in range(30)]) ).decode() diff --git a/cashu/mint/app.py b/cashu/mint/app.py index 078a939f..895945e8 100644 --- a/cashu/mint/app.py +++ b/cashu/mint/app.py @@ -3,6 +3,10 @@ from traceback import print_exception from fastapi import FastAPI, status +from fastapi.exception_handlers import ( + request_validation_exception_handler as _request_validation_exception_handler, +) +from fastapi.exceptions import RequestValidationError from fastapi.responses import JSONResponse # from fastapi_profiler import PyInstrumentProfilerMiddleware @@ -114,6 +118,12 @@ def emit(self, record): @app.middleware("http") async def catch_exceptions(request: Request, call_next): + CORS_HEADERS = { + "Access-Control-Allow-Origin": "*", + "Access-Control-Allow-Methods": "*", + "Access-Control-Allow-Headers": "*", + "Access-Control-Allow-Credentials": "true", + } try: return await call_next(request) except Exception as e: @@ -124,22 +134,44 @@ async def catch_exceptions(request: Request, call_next): if isinstance(e, CashuError): logger.error(f"CashuError: {err_message}") + # return with cors headers return JSONResponse( - status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + status_code=status.HTTP_400_BAD_REQUEST, content={"detail": err_message, "code": e.code}, + headers=CORS_HEADERS, ) logger.error(f"Exception: {err_message}") if settings.debug: print_exception(*sys.exc_info()) return JSONResponse( - status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + status_code=status.HTTP_400_BAD_REQUEST, content={"detail": err_message, "code": 0}, + headers=CORS_HEADERS, ) +async def request_validation_exception_handler( + request: Request, exc: RequestValidationError +) -> JSONResponse: + """ + This is a wrapper to the default RequestValidationException handler of FastAPI. + This function will be called when client input is not valid. + """ + query_params = request.query_params._dict + detail = { + "errors": exc.errors(), + "query_params": query_params, + } + # log the error + logger.error(detail) + # pass on + return await _request_validation_exception_handler(request, exc) + + @app.on_event("startup") async def startup_mint(): await start_mint_init() app.include_router(router=router) +app.add_exception_handler(RequestValidationError, request_validation_exception_handler) From 5e001548fe3975df54717e277d8a2f6ad32663a7 Mon Sep 17 00:00:00 2001 From: dyKiU <127620445+dyKiU@users.noreply.github.com> Date: Fri, 8 Sep 2023 15:42:01 +0100 Subject: [PATCH 9/9] load the proofs or we get a zero balance (#310) (cherry picked from commit 0e058fa69f53689c7d9d37f02b4f5a62c58f03e7) --- cashu/wallet/api/router.py | 1 + 1 file changed, 1 insertion(+) diff --git a/cashu/wallet/api/router.py b/cashu/wallet/api/router.py index 63820b9e..1f6fcaee 100644 --- a/cashu/wallet/api/router.py +++ b/cashu/wallet/api/router.py @@ -88,6 +88,7 @@ async def pay( global wallet wallet = await mint_wallet(mint) + await wallet.load_proofs(reload=True) total_amount, fee_reserve_sat = await wallet.get_pay_amount_with_fees(invoice) assert total_amount > 0, "amount has to be larger than zero."