From b98515df14f14d8d615442fcaed305cd34ecb7e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Wed, 3 Jun 2026 11:46:53 +0200 Subject: [PATCH] chore: update pyright to latest and fix new issues (#3978) --- lnbits/fiat/base.py | 6 +++--- lnbits/settings.py | 6 +++--- lnbits/wallets/base.py | 6 +++--- lnbits/wallets/blink.py | 12 +++++------- lnbits/wallets/breez.py | 6 ++++-- lnbits/wallets/breez_liquid.py | 2 +- lnbits/wallets/fake.py | 4 ++-- lnbits/wallets/lndgrpc.py | 2 +- package-lock.json | 13 ++++++++----- package.json | 2 +- tests/api/test_lnurl_api.py | 3 ++- tests/api/test_payment_api.py | 2 +- tests/unit/test_services_lnurl.py | 9 ++++++--- tests/unit/test_services_users.py | 3 ++- tests/unit/test_settings.py | 10 ++++++---- tests/wallets/test_blink.py | 3 ++- tests/wallets/test_rpc_wallets.py | 11 +++++++---- 17 files changed, 57 insertions(+), 43 deletions(-) diff --git a/lnbits/fiat/base.py b/lnbits/fiat/base.py index 126ed4d4c..15e39fb3b 100644 --- a/lnbits/fiat/base.py +++ b/lnbits/fiat/base.py @@ -131,15 +131,15 @@ class FiatSubscriptionResponse(BaseModel): class FiatPaymentSuccessStatus(FiatPaymentStatus): - paid = True + paid = True # type: ignore[reportIncompatibleVariableOverride] class FiatPaymentFailedStatus(FiatPaymentStatus): - paid = False + paid = False # type: ignore[reportIncompatibleVariableOverride] class FiatPaymentPendingStatus(FiatPaymentStatus): - paid = None + paid = None # type: ignore[reportIncompatibleVariableOverride] class FiatProvider(ABC): diff --git a/lnbits/settings.py b/lnbits/settings.py index 4923e8bf5..49e9eb5c6 100644 --- a/lnbits/settings.py +++ b/lnbits/settings.py @@ -1047,7 +1047,7 @@ class EditableSettings( class UpdateSettings(EditableSettings): - class Config: + class Config(EditableSettings.Config): extra = Extra.forbid @@ -1198,11 +1198,11 @@ class ReadOnlySettings( class Settings(EditableSettings, ReadOnlySettings, TransientSettings, BaseSettings): - class Config: + class Config(EditableSettings.Config, BaseSettings.Config): # type: ignore[misc] env_file = ".env" env_file_encoding = "utf-8" case_sensitive = False - json_loads = list_parse_fallback + json_loads = list_parse_fallback # type: ignore[assignment] def is_user_allowed(self, user_id: str) -> bool: return ( diff --git a/lnbits/wallets/base.py b/lnbits/wallets/base.py index 90517948d..4d1d81b95 100644 --- a/lnbits/wallets/base.py +++ b/lnbits/wallets/base.py @@ -94,15 +94,15 @@ class PaymentStatus(NamedTuple): class PaymentSuccessStatus(PaymentStatus): - paid = True + paid = True # type: ignore[reportIncompatibleVariableOverride] class PaymentFailedStatus(PaymentStatus): - paid = False + paid = False # type: ignore[reportIncompatibleVariableOverride] class PaymentPendingStatus(PaymentStatus): - paid = None + paid = None # type: ignore[reportIncompatibleVariableOverride] class Wallet(ABC): diff --git a/lnbits/wallets/blink.py b/lnbits/wallets/blink.py index be736086a..edc7d1c16 100644 --- a/lnbits/wallets/blink.py +++ b/lnbits/wallets/blink.py @@ -8,7 +8,7 @@ from loguru import logger from pydantic import BaseModel from websockets import Subprotocol, connect -from lnbits import bolt11 +from lnbits import bolt11 as bolt11_lib from lnbits.helpers import normalize_endpoint from lnbits.settings import settings @@ -164,15 +164,13 @@ class BlinkWallet(Wallet): ok=False, error_message=f"Unable to connect to {self.endpoint}." ) - async def pay_invoice( - self, bolt11_invoice: str, fee_limit_msat: int - ) -> PaymentResponse: + async def pay_invoice(self, bolt11: str, fee_limit_msat: int) -> PaymentResponse: # https://dev.blink.sv/api/btc-ln-send # Future: add check fee estimate is < fee_limit_msat before paying invoice payment_variables = { "input": { - "paymentRequest": bolt11_invoice, + "paymentRequest": bolt11, "walletId": self.wallet_id, "memo": "Payment memo", } @@ -190,7 +188,7 @@ class BlinkWallet(Wallet): error_message = errors[0].get("message") return PaymentResponse(ok=False, error_message=error_message) - checking_id = bolt11.decode(bolt11_invoice).payment_hash + checking_id = bolt11_lib.decode(bolt11).payment_hash payment_status = await self.get_payment_status(checking_id) fee_msat = payment_status.fee_msat @@ -199,7 +197,7 @@ class BlinkWallet(Wallet): ok=True, checking_id=checking_id, fee_msat=fee_msat, preimage=preimage ) except Exception as exc: - logger.info(f"Failed to pay invoice {bolt11_invoice}") + logger.info(f"Failed to pay invoice {bolt11}") logger.warning(exc) return PaymentResponse( error_message=f"Unable to connect to {self.endpoint}." diff --git a/lnbits/wallets/breez.py b/lnbits/wallets/breez.py index bf6d59c94..e32cb9b90 100644 --- a/lnbits/wallets/breez.py +++ b/lnbits/wallets/breez.py @@ -19,7 +19,7 @@ else: from bolt11 import Bolt11Exception from bolt11 import decode as bolt11_decode - from breez_sdk import ( + from breez_sdk import ( # type: ignore[reportMissingImports] BreezEvent, ConnectRequest, EnvironmentType, @@ -39,7 +39,9 @@ else: default_config, mnemonic_to_seed, ) - from breez_sdk import PaymentStatus as BreezPaymentStatus + from breez_sdk import ( + PaymentStatus as BreezPaymentStatus, # type: ignore[reportMissingImports] + ) from loguru import logger from lnbits.settings import settings diff --git a/lnbits/wallets/breez_liquid.py b/lnbits/wallets/breez_liquid.py index 6f1f6fb56..c2a649a90 100644 --- a/lnbits/wallets/breez_liquid.py +++ b/lnbits/wallets/breez_liquid.py @@ -18,7 +18,7 @@ else: from pathlib import Path from bolt11 import decode as bolt11_decode - from breez_sdk_liquid import ( + from breez_sdk_liquid import ( # type: ignore[reportMissingImports] ConnectRequest, EventListener, GetInfoResponse, diff --git a/lnbits/wallets/fake.py b/lnbits/wallets/fake.py index be70d5726..438c8401f 100644 --- a/lnbits/wallets/fake.py +++ b/lnbits/wallets/fake.py @@ -103,7 +103,7 @@ class FakeWallet(Wallet): preimage=preimage.hex(), ) - async def pay_invoice(self, bolt11: str, _: int) -> PaymentResponse: + async def pay_invoice(self, bolt11: str, fee_limit_msat: int) -> PaymentResponse: try: invoice = decode(bolt11) except Bolt11Exception as exc: @@ -130,7 +130,7 @@ class FakeWallet(Wallet): return PaymentPendingStatus() return PaymentFailedStatus() - async def get_payment_status(self, _: str) -> PaymentStatus: + async def get_payment_status(self, checking_id: str) -> PaymentStatus: return PaymentPendingStatus() async def paid_invoices_stream(self) -> AsyncGenerator[str, None]: diff --git a/lnbits/wallets/lndgrpc.py b/lnbits/wallets/lndgrpc.py index 878433e94..bef94153e 100644 --- a/lnbits/wallets/lndgrpc.py +++ b/lnbits/wallets/lndgrpc.py @@ -118,7 +118,7 @@ class LndWallet(Wallet): cert = open(cert_path, "rb").read() creds = grpc.ssl_channel_credentials(cert) - auth_creds = grpc.metadata_call_credentials(self.metadata_callback) + auth_creds = grpc.metadata_call_credentials(self.metadata_callback) # type: ignore[reportArgumentType] composite_creds = grpc.composite_channel_credentials(creds, auth_creds) channel = grpc.aio.secure_channel( f"{self.endpoint}:{self.port}", composite_creds diff --git a/package-lock.json b/package-lock.json index 504026266..7291a746f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,7 +24,7 @@ "clean-css-cli": "^5.6.3", "concat": "^1.0.3", "prettier": "^3.8.3", - "pyright": "1.1.289", + "pyright": "1.1.409", "sass": "^1.99.0", "terser": "^5.47.1" } @@ -1808,9 +1808,9 @@ } }, "node_modules/pyright": { - "version": "1.1.289", - "resolved": "https://registry.npmjs.org/pyright/-/pyright-1.1.289.tgz", - "integrity": "sha512-fG3STxnwAt3i7bxbXUPJdYNFrcOWHLwCSEOySH2foUqtYdzWLcxDez0Kgl1X8LMQx0arMJ6HRkKghxfRD1/z6g==", + "version": "1.1.409", + "resolved": "https://registry.npmjs.org/pyright/-/pyright-1.1.409.tgz", + "integrity": "sha512-13VFQyw4mJzshZxcxiYbNjo1hG/WHSRDj70Y3lbJEHqCkI2dvBAUTti8VV6Ezsr5gT93pFvC0e/jAQS4JdHarA==", "dev": true, "license": "MIT", "bin": { @@ -1818,7 +1818,10 @@ "pyright-langserver": "langserver.index.js" }, "engines": { - "node": ">=12.0.0" + "node": ">=14.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" } }, "node_modules/qrcode.vue": { diff --git a/package.json b/package.json index 9dfa1c7e2..105e42d78 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "clean-css-cli": "^5.6.3", "concat": "^1.0.3", "prettier": "^3.8.3", - "pyright": "1.1.289", + "pyright": "1.1.409", "sass": "^1.99.0", "terser": "^5.47.1" }, diff --git a/tests/api/test_lnurl_api.py b/tests/api/test_lnurl_api.py index 5cbdba40a..80dc63500 100644 --- a/tests/api/test_lnurl_api.py +++ b/tests/api/test_lnurl_api.py @@ -1,3 +1,4 @@ +from typing import cast from uuid import uuid4 import pytest @@ -106,7 +107,7 @@ async def test_lnurl_api_auth_and_pay_flow(mocker): await api_perform_lnurlauth(auth_response, wallet_info) action_response = LnurlPayActionResponse( - pr=LightningInvoice(TEST_BOLT11), + pr=cast(LightningInvoice, LightningInvoice(TEST_BOLT11)), disposable=False, successAction=parse_obj_as(MessageAction, {"message": "paid"}), ) diff --git a/tests/api/test_payment_api.py b/tests/api/test_payment_api.py index 3e0102014..95339b2d0 100644 --- a/tests/api/test_payment_api.py +++ b/tests/api/test_payment_api.py @@ -161,7 +161,7 @@ async def test_payment_api_fee_reserve_and_hold_invoice_actions(mocker): wallet.id, CreateInvoice(out=False, amount=42, memo="reserve") ) reserve = await api_payments_fee_reserve(invoice.bolt11) - assert json.loads(reserve.body)["fee_reserve"] >= 0 + assert json.loads(bytes(reserve.body))["fee_reserve"] >= 0 with pytest.raises(HTTPException, match="Invoice has no amount."): await api_payments_fee_reserve(ZERO_AMOUNT_INVOICE) diff --git a/tests/unit/test_services_lnurl.py b/tests/unit/test_services_lnurl.py index 4145da67e..d07a45a90 100644 --- a/tests/unit/test_services_lnurl.py +++ b/tests/unit/test_services_lnurl.py @@ -1,3 +1,4 @@ +from typing import cast from uuid import uuid4 import pytest @@ -86,7 +87,9 @@ async def test_get_pr_from_lnurl_success_and_error(mocker: MockerFixture): mocker.patch( "lnbits.core.services.lnurl.execute_pay_request", mocker.AsyncMock( - return_value=LnurlPayActionResponse(pr=LightningInvoice(TEST_BOLT11)) + return_value=LnurlPayActionResponse( + pr=cast(LightningInvoice, LightningInvoice(TEST_BOLT11)) + ) ), ) @@ -106,7 +109,7 @@ async def test_fetch_lnurl_pay_request_converts_currency_and_stores_paylink( ): pay_response = make_lnurl_pay_response(min_sendable_msat=1, text="Test") action_response = LnurlPayActionResponse( - pr=LightningInvoice(TEST_BOLT11), disposable=False + pr=cast(LightningInvoice, LightningInvoice(TEST_BOLT11)), disposable=False ) mocker.patch( "lnbits.core.services.lnurl.fiat_amount_as_satoshis", @@ -143,7 +146,7 @@ async def test_store_paylink_appends_and_updates_existing(): wallet = await _create_wallet() pay_response = make_lnurl_pay_response(min_sendable_msat=1, text="Test") action_response = LnurlPayActionResponse( - pr=LightningInvoice(TEST_BOLT11), disposable=False + pr=cast(LightningInvoice, LightningInvoice(TEST_BOLT11)), disposable=False ) await store_paylink( diff --git a/tests/unit/test_services_users.py b/tests/unit/test_services_users.py index be16d3ce7..0e656c5e8 100644 --- a/tests/unit/test_services_users.py +++ b/tests/unit/test_services_users.py @@ -1,3 +1,4 @@ +from typing import Any from uuid import uuid4 import pytest @@ -66,7 +67,7 @@ async def test_create_user_account_no_check_rejects_duplicate_identity_fields( existing = _account(**existing_data) await create_account(existing) - resolved = { + resolved: dict[str, Any] = { key: (value(existing) if callable(value) else value) for key, value in new_data.items() } diff --git a/tests/unit/test_settings.py b/tests/unit/test_settings.py index bc34d1565..d1fecc856 100644 --- a/tests/unit/test_settings.py +++ b/tests/unit/test_settings.py @@ -1,3 +1,5 @@ +from typing import Any + import pytest from pytest_mock.plugin import MockerFixture @@ -14,22 +16,22 @@ from lnbits.settings import ( set_cli_settings, ) -lnurlp_redirect_path = { +lnurlp_redirect_path: dict[str, Any] = { "from_path": "/.well-known/lnurlp", "redirect_to_path": "/api/v1/well-known", } -lnurlp_redirect_path_with_headers = { +lnurlp_redirect_path_with_headers: dict[str, Any] = { "from_path": "/.well-known/lnurlp", "redirect_to_path": "/api/v1/well-known", "header_filters": {"accept": "application/nostr+json"}, } -lnaddress_redirect_path = { +lnaddress_redirect_path: dict[str, Any] = { "from_path": "/.well-known/lnurlp", "redirect_to_path": "/api/v1/well-known", } -nostrrelay_redirect_path = { +nostrrelay_redirect_path: dict[str, Any] = { "from_path": "/", "redirect_to_path": "/api/v1/relay-info", "header_filters": {"accept": "application/nostr+json"}, diff --git a/tests/wallets/test_blink.py b/tests/wallets/test_blink.py index b07271a7d..8a6ae65ba 100644 --- a/tests/wallets/test_blink.py +++ b/tests/wallets/test_blink.py @@ -1,4 +1,5 @@ import os +from typing import cast import pytest from loguru import logger @@ -29,7 +30,7 @@ logger.info(f"settings.blink_api_endpoint: {settings.blink_api_endpoint}") logger.info(f"settings.blink_token: {settings.blink_token}") set_funding_source() -funding_source = get_funding_source() +funding_source = cast(BlinkWallet, get_funding_source()) assert isinstance(funding_source, BlinkWallet) diff --git a/tests/wallets/test_rpc_wallets.py b/tests/wallets/test_rpc_wallets.py index e76c82cd9..51c3810c7 100644 --- a/tests/wallets/test_rpc_wallets.py +++ b/tests/wallets/test_rpc_wallets.py @@ -1,4 +1,5 @@ import importlib +from typing import Any from unittest.mock import AsyncMock, Mock import pytest @@ -80,7 +81,9 @@ def _check_calls(expected_calls): for func_call in func_calls: req = func_call["request_data"] args = req["args"] if "args" in req else {} - kwargs = _eval_dict(req["kwargs"]) if "kwargs" in req else {} + kwargs: dict[str, Any] = ( + _eval_dict(req["kwargs"]) or {} if "kwargs" in req else {} + ) if "klass" in req: *rest, cls = req["klass"].split(".") @@ -166,7 +169,7 @@ def _mock_field(field): return response -def _eval_dict(data: dict | None) -> dict | None: +def _eval_dict(data: dict | None) -> dict[str, Any] | None: fn_prefix = "__eval__:" if not data: return data @@ -215,9 +218,9 @@ def _data_mock(data: dict) -> Mock: def _raise(error: dict | None): if not error: return Exception() - data = error["data"] if "data" in error else None + data: dict[str, Any] = error["data"] if "data" in error else {} if "module" not in error or "class" not in error: - return Exception(data) + return Exception(data or None) error_module = importlib.import_module(error["module"]) error_class = getattr(error_module, error["class"])