chore: adhere to ruff's "N" rules (#2377)

* chore: adhere to ruff's "N" rules

WARN: reinstall failing extensions!

bunch of more consistent variable naming. inspired by this issue.
https://github.com/lnbits/lnbits/issues/2308

* fixup! chore: adhere to ruff's "N" rules
* rename to funding_source
* skip jmeter

---------

Co-authored-by: Pavol Rusnak <pavol@rusnak.io>
This commit is contained in:
dni ⚡ 2024-04-15 09:02:21 +02:00 committed by GitHub
parent 055426ab53
commit 6d5ad9e229
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
28 changed files with 191 additions and 173 deletions

View file

@ -53,13 +53,13 @@ jobs:
secrets:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
jmeter:
needs: [ lint ]
strategy:
matrix:
python-version: ["3.9"]
poetry-version: ["1.5.1"]
uses: ./.github/workflows/jmeter.yml
with:
python-version: ${{ matrix.python-version }}
poetry-version: ${{ matrix.poetry-version }}
# jmeter:
# needs: [ lint ]
# strategy:
# matrix:
# python-version: ["3.9"]
# poetry-version: ["1.5.1"]
# uses: ./.github/workflows/jmeter.yml
# with:
# python-version: ${{ matrix.python-version }}
# poetry-version: ${{ matrix.poetry-version }}

View file

@ -25,7 +25,7 @@ from starlette.responses import JSONResponse
from lnbits.core.crud import get_dbversions, get_installed_extensions
from lnbits.core.helpers import migrate_extension_database
from lnbits.core.services import websocketUpdater
from lnbits.core.services import websocket_updater
from lnbits.core.tasks import ( # watchdog_task
killswitch_task,
wait_for_paid_invoices,
@ -37,7 +37,7 @@ from lnbits.tasks import (
register_invoice_listener,
)
from lnbits.utils.cache import cache
from lnbits.wallets import get_wallet_class, set_wallet_class
from lnbits.wallets import get_funding_source, set_funding_source
from .commands import migrate_databases
from .core import init_core_routers
@ -81,7 +81,7 @@ async def startup(app: FastAPI):
# initialize WALLET
try:
set_wallet_class()
set_funding_source()
except Exception as e:
logger.error(f"Error initializing {settings.lnbits_backend_wallet_class}: {e}")
set_void_wallet_class()
@ -110,8 +110,8 @@ async def shutdown():
# wait a bit to allow them to finish, so that cleanup can run without problems
await asyncio.sleep(0.1)
WALLET = get_wallet_class()
await WALLET.cleanup()
funding_source = get_funding_source()
await funding_source.cleanup()
@asynccontextmanager
@ -178,33 +178,35 @@ def create_app() -> FastAPI:
async def check_funding_source() -> None:
WALLET = get_wallet_class()
funding_source = get_funding_source()
max_retries = settings.funding_source_max_retries
retry_counter = 0
while True:
try:
logger.info(f"Connecting to backend {WALLET.__class__.__name__}...")
error_message, balance = await WALLET.status()
logger.info(f"Connecting to backend {funding_source.__class__.__name__}...")
error_message, balance = await funding_source.status()
if not error_message:
retry_counter = 0
logger.success(
f"✔️ Backend {WALLET.__class__.__name__} connected "
f"✔️ Backend {funding_source.__class__.__name__} connected "
f"and with a balance of {balance} msat."
)
break
logger.error(
f"The backend for {WALLET.__class__.__name__} isn't "
f"The backend for {funding_source.__class__.__name__} isn't "
f"working properly: '{error_message}'",
RuntimeWarning,
)
except Exception as e:
logger.error(f"Error connecting to {WALLET.__class__.__name__}: {e}")
logger.error(
f"Error connecting to {funding_source.__class__.__name__}: {e}"
)
if retry_counter >= max_retries:
set_void_wallet_class()
WALLET = get_wallet_class()
funding_source = get_funding_source()
break
retry_counter += 1
@ -221,7 +223,7 @@ def set_void_wallet_class():
"Fallback to VoidWallet, because the backend for "
f"{settings.lnbits_backend_wallet_class} isn't working properly"
)
set_wallet_class("VoidWallet")
set_funding_source("VoidWallet")
async def check_installed_extensions(app: FastAPI):
@ -414,7 +416,7 @@ def initialize_server_logger():
async def update_websocket_serverlog():
while True:
msg = await serverlog_queue.get()
await websocketUpdater(super_user_hash, msg)
await websocket_updater(super_user_hash, msg)
create_permanent_task(update_websocket_serverlog)

View file

@ -17,7 +17,7 @@ from lnbits.db import Connection, FilterModel, FromRowModel
from lnbits.helpers import url_for
from lnbits.lnurl import encode as lnurl_encode
from lnbits.settings import settings
from lnbits.wallets import get_wallet_class
from lnbits.wallets import get_funding_source
from lnbits.wallets.base import PaymentPendingStatus, PaymentStatus
@ -265,11 +265,11 @@ class Payment(FromRowModel):
f"pending payment {self.checking_id}"
)
WALLET = get_wallet_class()
funding_source = get_funding_source()
if self.is_out:
status = await WALLET.get_payment_status(self.checking_id)
status = await funding_source.get_payment_status(self.checking_id)
else:
status = await WALLET.get_invoice_status(self.checking_id)
status = await funding_source.get_invoice_status(self.checking_id)
logger.debug(f"Status: {status}")

View file

@ -30,7 +30,7 @@ from lnbits.settings import (
settings,
)
from lnbits.utils.exchange_rates import fiat_amount_as_satoshis, satoshis_amount_as_fiat
from lnbits.wallets import FAKE_WALLET, get_wallet_class, set_wallet_class
from lnbits.wallets import fake_wallet, get_funding_source, set_funding_source
from lnbits.wallets.base import (
PaymentPendingStatus,
PaymentResponse,
@ -62,11 +62,11 @@ from .helpers import to_valid_user_id
from .models import Payment, UserConfig, Wallet
class PaymentFailure(Exception):
class PaymentError(Exception):
pass
class InvoiceFailure(Exception):
class InvoiceError(Exception):
pass
@ -123,16 +123,16 @@ async def create_invoice(
conn: Optional[Connection] = None,
) -> Tuple[str, str]:
if not amount > 0:
raise InvoiceFailure("Amountless invoices not supported.")
raise InvoiceError("Amountless invoices not supported.")
user_wallet = await get_wallet(wallet_id, conn=conn)
if not user_wallet:
raise InvoiceFailure(f"Could not fetch wallet '{wallet_id}'.")
raise InvoiceError(f"Could not fetch wallet '{wallet_id}'.")
invoice_memo = None if description_hash else memo
# use the fake wallet if the invoice is for internal use only
wallet = FAKE_WALLET if internal else get_wallet_class()
funding_source = fake_wallet if internal else get_funding_source()
amount_sat, extra = await calculate_fiat_amounts(
amount, wallet_id, currency=currency, extra=extra, conn=conn
@ -141,20 +141,22 @@ async def create_invoice(
if settings.is_wallet_max_balance_exceeded(
user_wallet.balance_msat / 1000 + amount_sat
):
raise InvoiceFailure(
raise InvoiceError(
f"Wallet balance cannot exceed "
f"{settings.lnbits_wallet_limit_max_balance} sats."
)
ok, checking_id, payment_request, error_message = await wallet.create_invoice(
amount=amount_sat,
memo=invoice_memo,
description_hash=description_hash,
unhashed_description=unhashed_description,
expiry=expiry or settings.lightning_invoice_expiry,
ok, checking_id, payment_request, error_message = (
await funding_source.create_invoice(
amount=amount_sat,
memo=invoice_memo,
description_hash=description_hash,
unhashed_description=unhashed_description,
expiry=expiry or settings.lightning_invoice_expiry,
)
)
if not ok or not payment_request or not checking_id:
raise InvoiceFailure(error_message or "unexpected backend error.")
raise InvoiceError(error_message or "unexpected backend error.")
invoice = bolt11_decode(payment_request)
@ -197,12 +199,12 @@ async def pay_invoice(
try:
invoice = bolt11_decode(payment_request)
except Exception:
raise InvoiceFailure("Bolt11 decoding failed.")
raise InvoiceError("Bolt11 decoding failed.")
if not invoice.amount_msat or not invoice.amount_msat > 0:
raise InvoiceFailure("Amountless invoices not supported.")
raise InvoiceError("Amountless invoices not supported.")
if max_sat and invoice.amount_msat > max_sat * 1000:
raise InvoiceFailure("Amount in invoice is too high.")
raise InvoiceError("Amount in invoice is too high.")
await check_wallet_limits(wallet_id, conn, invoice.amount_msat)
@ -237,7 +239,7 @@ async def pay_invoice(
# we check if an internal invoice exists that has already been paid
# (not pending anymore)
if not await check_internal_pending(invoice.payment_hash, conn=conn):
raise PaymentFailure("Internal invoice already paid.")
raise PaymentError("Internal invoice already paid.")
# check_internal() returns the checking_id of the invoice we're waiting for
# (pending only)
@ -256,7 +258,7 @@ async def pay_invoice(
internal_invoice.amount != invoice.amount_msat
or internal_invoice.bolt11 != payment_request.lower()
):
raise PaymentFailure("Invalid invoice.")
raise PaymentError("Invalid invoice.")
logger.debug(f"creating temporary internal payment with id {internal_id}")
# create a new payment from this wallet
@ -284,7 +286,7 @@ async def pay_invoice(
except Exception as e:
logger.error(f"could not create temporary payment: {e}")
# happens if the same wallet tries to pay an invoice twice
raise PaymentFailure("Could not make payment.")
raise PaymentError("Could not make payment.")
# do the balance check
wallet = await get_wallet(wallet_id, conn=conn)
@ -295,7 +297,7 @@ async def pay_invoice(
not internal_checking_id
and wallet.balance_msat > -fee_reserve_total_msat
):
raise PaymentFailure(
raise PaymentError(
f"You must reserve at least ({round(fee_reserve_total_msat/1000)}"
" sat) to cover potential routing fees."
)
@ -323,8 +325,8 @@ async def pay_invoice(
service_fee_msat = service_fee(invoice.amount_msat, internal=False)
logger.debug(f"backend: sending payment {temp_id}")
# actually pay the external invoice
WALLET = get_wallet_class()
payment: PaymentResponse = await WALLET.pay_invoice(
funding_source = get_funding_source()
payment: PaymentResponse = await funding_source.pay_invoice(
payment_request, fee_reserve_msat
)
@ -363,7 +365,7 @@ async def pay_invoice(
async with db.connect() as conn:
logger.debug(f"deleting temporary payment {temp_id}")
await delete_wallet_payment(temp_id, wallet_id, conn=conn)
raise PaymentFailure(
raise PaymentError(
f"Payment failed: {payment.error_message}"
or "Payment failed, but backend didn't give us an error message."
)
@ -499,7 +501,6 @@ async def redeem_lnurl_withdraw(
async def perform_lnurlauth(
callback: str,
wallet: WalletTypeInfo = Depends(require_admin_key),
conn: Optional[Connection] = None,
) -> Optional[LnurlErrorResponse]:
cb = urlparse(callback)
@ -592,7 +593,7 @@ async def check_transaction_status(
# WARN: this same value must be used for balance check and passed to
# WALLET.pay_invoice(), it may cause a vulnerability if the values differ
# funding_source.pay_invoice(), it may cause a vulnerability if the values differ
def fee_reserve(amount_msat: int, internal: bool = False) -> int:
if internal:
return 0
@ -621,7 +622,7 @@ def fee_reserve_total(amount_msat: int, internal: bool = False) -> int:
async def send_payment_notification(wallet: Wallet, payment: Payment):
await websocketUpdater(
await websocket_updater(
wallet.id,
json.dumps(
{
@ -760,25 +761,25 @@ class WebsocketConnectionManager:
await connection.send_text(message)
websocketManager = WebsocketConnectionManager()
websocket_manager = WebsocketConnectionManager()
async def websocketUpdater(item_id, data):
return await websocketManager.send_data(f"{data}", item_id)
async def websocket_updater(item_id, data):
return await websocket_manager.send_data(f"{data}", item_id)
async def switch_to_voidwallet() -> None:
WALLET = get_wallet_class()
if WALLET.__class__.__name__ == "VoidWallet":
funding_source = get_funding_source()
if funding_source.__class__.__name__ == "VoidWallet":
return
set_wallet_class("VoidWallet")
set_funding_source("VoidWallet")
settings.lnbits_backend_wallet_class = "VoidWallet"
async def get_balance_delta() -> Tuple[int, int, int]:
WALLET = get_wallet_class()
funding_source = get_funding_source()
total_balance = await get_total_balance()
error_message, node_balance = await WALLET.status()
error_message, node_balance = await funding_source.status()
if error_message:
raise Exception(error_message)
return node_balance - total_balance, node_balance, total_balance

View file

@ -16,7 +16,7 @@ from lnbits.core.services import (
send_payment_notification,
switch_to_voidwallet,
)
from lnbits.settings import get_wallet_class, settings
from lnbits.settings import get_funding_source, settings
from lnbits.tasks import send_push_notification
api_invoice_listeners: Dict[str, asyncio.Queue] = {}
@ -28,8 +28,11 @@ async def killswitch_task():
LNbits and will switch to VoidWallet if the killswitch is triggered.
"""
while True:
WALLET = get_wallet_class()
if settings.lnbits_killswitch and WALLET.__class__.__name__ != "VoidWallet":
funding_source = get_funding_source()
if (
settings.lnbits_killswitch
and funding_source.__class__.__name__ != "VoidWallet"
):
with httpx.Client() as client:
try:
r = client.get(settings.lnbits_status_manifest, timeout=4)
@ -55,8 +58,11 @@ async def watchdog_task():
and will switch to VoidWallet if the watchdog delta is reached.
"""
while True:
WALLET = get_wallet_class()
if settings.lnbits_watchdog and WALLET.__class__.__name__ != "VoidWallet":
funding_source = get_funding_source()
if (
settings.lnbits_watchdog
and funding_source.__class__.__name__ != "VoidWallet"
):
try:
delta, *_ = await get_balance_delta()
logger.debug(f"Running watchdog task. current delta: {delta}")

View file

@ -316,16 +316,16 @@ def _new_sso(provider: str) -> Optional[SSOBase]:
logger.warning(f"{provider} auth allowed but not configured.")
return None
SSOProviderClass = _find_auth_provider_class(provider)
ssoProvider = SSOProviderClass(
sso_provider_class = _find_auth_provider_class(provider)
sso_provider = sso_provider_class(
client_id, client_secret, None, allow_insecure_http=True
)
if (
discovery_url
and getattr(ssoProvider, "discovery_url", discovery_url) != discovery_url
and getattr(sso_provider, "discovery_url", discovery_url) != discovery_url
):
ssoProvider.discovery_url = discovery_url
return ssoProvider
sso_provider.discovery_url = discovery_url
return sso_provider
except Exception as e:
logger.warning(e)
@ -337,9 +337,9 @@ def _find_auth_provider_class(provider: str) -> Callable:
for module in sso_modules:
try:
provider_module = importlib.import_module(f"{module}.{provider}")
ProviderClass = getattr(provider_module, f"{provider.title()}SSO")
if ProviderClass:
return ProviderClass
provider_class = getattr(provider_module, f"{provider.title()}SSO")
if provider_class:
return provider_class
except Exception:
pass

View file

@ -18,7 +18,7 @@ from lnbits.core.models import User
from lnbits.decorators import check_admin, check_user_exists
from lnbits.helpers import template_renderer, url_for
from lnbits.settings import settings
from lnbits.wallets import get_wallet_class
from lnbits.wallets import get_funding_source
from ...extension_manager import InstallableExtension, get_valid_extensions
from ...utils.exchange_rates import allowed_currencies, currencies
@ -452,8 +452,8 @@ async def node(request: Request, user: User = Depends(check_admin)):
if not settings.lnbits_node_ui:
raise HTTPException(status_code=HTTPStatus.SERVICE_UNAVAILABLE)
WALLET = get_wallet_class()
_, balance = await WALLET.status()
funding_source = get_funding_source()
_, balance = await funding_source.status()
return template_renderer().TemplateResponse(
request,
@ -472,8 +472,8 @@ async def node_public(request: Request):
if not settings.lnbits_public_node_ui:
raise HTTPException(status_code=HTTPStatus.SERVICE_UNAVAILABLE)
WALLET = get_wallet_class()
_, balance = await WALLET.status()
funding_source = get_funding_source()
_, balance = await funding_source.status()
return template_renderer().TemplateResponse(
request,
@ -490,8 +490,8 @@ async def index(request: Request, user: User = Depends(check_admin)):
if not settings.lnbits_admin_ui:
raise HTTPException(status_code=HTTPStatus.NOT_FOUND)
WALLET = get_wallet_class()
_, balance = await WALLET.status()
funding_source = get_funding_source()
_, balance = await funding_source.status()
return template_renderer().TemplateResponse(
request,

View file

@ -27,8 +27,8 @@ from ...utils.cache import cache
def require_node():
NODE = get_node_class()
if not NODE:
node_class = get_node_class()
if not node_class:
raise HTTPException(
status_code=HTTPStatus.NOT_IMPLEMENTED,
detail="Active backend does not implement Node API",
@ -38,7 +38,7 @@ def require_node():
status_code=HTTPStatus.SERVICE_UNAVAILABLE,
detail="Not enabled",
)
return NODE
return node_class
def check_public():

View file

@ -56,8 +56,8 @@ from ..crud import (
update_pending_payments,
)
from ..services import (
InvoiceFailure,
PaymentFailure,
InvoiceError,
PaymentError,
check_transaction_status,
create_invoice,
fee_reserve_total,
@ -171,7 +171,7 @@ async def api_payments_create_invoice(data: CreateInvoice, wallet: Wallet):
payment_db = await get_standalone_payment(payment_hash, conn=conn)
assert payment_db is not None, "payment not found"
checking_id = payment_db.checking_id
except InvoiceFailure as e:
except InvoiceError as e:
raise HTTPException(status_code=520, detail=str(e))
except Exception as exc:
raise exc
@ -230,7 +230,7 @@ async def api_payments_pay_invoice(
raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, detail=str(e))
except PermissionError as e:
raise HTTPException(status_code=HTTPStatus.FORBIDDEN, detail=str(e))
except PaymentFailure as e:
except PaymentError as e:
raise HTTPException(status_code=520, detail=str(e))
except Exception as exc:
raise exc
@ -257,20 +257,20 @@ async def api_payments_pay_invoice(
)
async def api_payments_create(
wallet: WalletTypeInfo = Depends(require_invoice_key),
invoiceData: CreateInvoice = Body(...),
invoice_data: CreateInvoice = Body(...),
):
if invoiceData.out is True and wallet.wallet_type == WalletType.admin:
if not invoiceData.bolt11:
if invoice_data.out is True and wallet.wallet_type == WalletType.admin:
if not invoice_data.bolt11:
raise HTTPException(
status_code=HTTPStatus.BAD_REQUEST,
detail="BOLT11 string is invalid or not given",
)
return await api_payments_pay_invoice(
invoiceData.bolt11, wallet.wallet, invoiceData.extra
invoice_data.bolt11, wallet.wallet, invoice_data.extra
) # admin key
elif not invoiceData.out:
elif not invoice_data.out:
# invoice key
return await api_payments_create_invoice(invoiceData, wallet.wallet)
return await api_payments_create_invoice(invoice_data, wallet.wallet)
else:
raise HTTPException(
status_code=HTTPStatus.UNAUTHORIZED,
@ -415,10 +415,10 @@ async def api_payments_sse(
# TODO: refactor this route into a public and admin one
@payment_router.get("/{payment_hash}")
async def api_payment(payment_hash, X_Api_Key: Optional[str] = Header(None)):
async def api_payment(payment_hash, x_api_key: Optional[str] = Header(None)):
# We use X_Api_Key here because we want this call to work with and without keys
# If a valid key is given, we also return the field "details", otherwise not
wallet = await get_wallet_for_key(X_Api_Key) if isinstance(X_Api_Key, str) else None
wallet = await get_wallet_for_key(x_api_key) if isinstance(x_api_key, str) else None
payment = await get_standalone_payment(
payment_hash, wallet_id=wallet.id if wallet else None

View file

@ -5,8 +5,8 @@ from fastapi import (
)
from ..services import (
websocketManager,
websocketUpdater,
websocket_manager,
websocket_updater,
)
websocket_router = APIRouter(prefix="/api/v1/ws", tags=["Websocket"])
@ -14,18 +14,18 @@ websocket_router = APIRouter(prefix="/api/v1/ws", tags=["Websocket"])
@websocket_router.websocket("/{item_id}")
async def websocket_connect(websocket: WebSocket, item_id: str):
await websocketManager.connect(websocket, item_id)
await websocket_manager.connect(websocket, item_id)
try:
while True:
await websocket.receive_text()
except WebSocketDisconnect:
websocketManager.disconnect(websocket)
websocket_manager.disconnect(websocket)
@websocket_router.post("/{item_id}")
async def websocket_update_post(item_id: str, data: str):
try:
await websocketUpdater(item_id, data)
await websocket_updater(item_id, data)
return {"sent": True, "data": data}
except Exception:
return {"sent": False, "data": data}
@ -34,7 +34,7 @@ async def websocket_update_post(item_id: str, data: str):
@websocket_router.get("/{item_id}/{data}")
async def websocket_update_get(item_id: str, data: str):
try:
await websocketUpdater(item_id, data)
await websocket_updater(item_id, data)
return {"sent": True, "data": data}
except Exception:
return {"sent": False, "data": data}

View file

@ -140,14 +140,14 @@ class Connection(Compat):
def rewrite_values(self, values):
# strip html
CLEANR = re.compile("<.*?>|&([a-z0-9]+|#[0-9]{1,6}|#x[0-9a-f]{1,6});")
clean_regex = re.compile("<.*?>|&([a-z0-9]+|#[0-9]{1,6}|#x[0-9a-f]{1,6});")
# tuple to list and back to tuple
raw_values = [values] if isinstance(values, str) else list(values)
values = []
for raw_value in raw_values:
if isinstance(raw_value, str):
values.append(re.sub(CLEANR, "", raw_value))
values.append(re.sub(clean_regex, "", raw_value))
elif isinstance(raw_value, datetime.datetime):
ts = raw_value.timestamp()
if self.type == SQLITE:

View file

@ -138,12 +138,12 @@ async def get_key_type(
detail="Invoice (or Admin) key required.",
)
for wallet_type, WalletChecker in zip(
for wallet_type, wallet_checker in zip(
[WalletType.admin, WalletType.invoice],
[WalletAdminKeyChecker, WalletInvoiceKeyChecker],
):
try:
checker = WalletChecker(api_key=token)
checker = wallet_checker(api_key=token)
await checker.__call__(r)
if checker.wallet is None:
raise HTTPException(

View file

@ -532,10 +532,10 @@ if not settings.lnbits_admin_ui:
logger.debug(f"{key}: {value}")
def get_wallet_class():
def get_funding_source():
"""
Backwards compatibility
"""
from lnbits.wallets import get_wallet_class
from lnbits.wallets import get_funding_source
return get_wallet_class()
return get_funding_source()

View file

@ -17,7 +17,7 @@ from lnbits.core.crud import (
get_standalone_payment,
)
from lnbits.settings import settings
from lnbits.wallets import get_wallet_class
from lnbits.wallets import get_funding_source
tasks: List[asyncio.Task] = []
unique_tasks: Dict[str, asyncio.Task] = {}
@ -119,8 +119,8 @@ async def invoice_listener():
Called by the app startup sequence.
"""
WALLET = get_wallet_class()
async for checking_id in WALLET.paid_invoices_stream():
funding_source = get_funding_source()
async for checking_id in funding_source.paid_invoices_stream():
logger.info("> got a payment notification", checking_id)
create_task(invoice_callback_dispatcher(checking_id))

View file

@ -28,21 +28,21 @@ from .void import VoidWallet
from .zbd import ZBDWallet
def set_wallet_class(class_name: Optional[str] = None):
def set_funding_source(class_name: Optional[str] = None):
backend_wallet_class = class_name or settings.lnbits_backend_wallet_class
wallet_class = getattr(wallets_module, backend_wallet_class)
global WALLET
WALLET = wallet_class()
if WALLET.__node_cls__:
set_node_class(WALLET.__node_cls__(WALLET))
funding_source_constructor = getattr(wallets_module, backend_wallet_class)
global funding_source
funding_source = funding_source_constructor()
if funding_source.__node_cls__:
set_node_class(funding_source.__node_cls__(funding_source))
def get_wallet_class() -> Wallet:
return WALLET
def get_funding_source() -> Wallet:
return funding_source
wallets_module = importlib.import_module("lnbits.wallets")
FAKE_WALLET = FakeWallet()
fake_wallet = FakeWallet()
# initialize as fake wallet
WALLET: Wallet = FAKE_WALLET
funding_source: Wallet = fake_wallet

View file

@ -144,5 +144,5 @@ class Wallet(ABC):
return endpoint
class Unsupported(Exception):
class UnsupportedError(Exception):
pass

View file

@ -18,7 +18,7 @@ from .base import (
PaymentStatus,
PaymentSuccessStatus,
StatusResponse,
Unsupported,
UnsupportedError,
Wallet,
)
@ -73,12 +73,12 @@ class CoreLightningWallet(Wallet):
msat: int = int(amount * 1000)
try:
if description_hash and not unhashed_description:
raise Unsupported(
raise UnsupportedError(
"'description_hash' unsupported by CoreLightning, provide"
" 'unhashed_description'"
)
if unhashed_description and not self.supports_description_hash:
raise Unsupported("unhashed_description")
raise UnsupportedError("unhashed_description")
r: dict = self.ln.invoice( # type: ignore
msatoshi=msat,
label=label,

View file

@ -16,7 +16,7 @@ from .base import (
PaymentResponse,
PaymentStatus,
StatusResponse,
Unsupported,
UnsupportedError,
Wallet,
)
from .macaroon import load_macaroon
@ -104,7 +104,7 @@ class CoreLightningRestWallet(Wallet):
"label": label,
}
if description_hash and not unhashed_description:
raise Unsupported(
raise UnsupportedError(
"'description_hash' unsupported by CoreLightningRest, "
"provide 'unhashed_description'"
)

View file

@ -40,8 +40,8 @@ class EclairWallet(Wallet):
self.ws_url = f"ws://{urllib.parse.urlsplit(self.url).netloc}/ws"
password = settings.eclair_pass
encodedAuth = base64.b64encode(f":{password}".encode())
auth = str(encodedAuth, "utf-8")
encoded_auth = base64.b64encode(f":{password}".encode())
auth = str(encoded_auth, "utf-8")
self.headers = {
"Authorization": f"Basic {auth}",
"User-Agent": settings.user_agent,

View file

@ -164,13 +164,13 @@ class LndRestWallet(Wallet):
async def pay_invoice(self, bolt11: str, fee_limit_msat: int) -> PaymentResponse:
# set the fee limit for the payment
lnrpcFeeLimit = {}
lnrpcFeeLimit["fixed_msat"] = f"{fee_limit_msat}"
lnrpc_fee_limit = {}
lnrpc_fee_limit["fixed_msat"] = f"{fee_limit_msat}"
try:
r = await self.client.post(
url="/v1/channels/transactions",
json={"payment_request": bolt11, "fee_limit": lnrpcFeeLimit},
json={"payment_request": bolt11, "fee_limit": lnrpc_fee_limit},
timeout=None,
)
r.raise_for_status()

View file

@ -12,7 +12,7 @@ from .base import (
PaymentResponse,
PaymentStatus,
StatusResponse,
Unsupported,
UnsupportedError,
Wallet,
)
@ -74,7 +74,7 @@ class OpenNodeWallet(Wallet):
**kwargs,
) -> InvoiceResponse:
if description_hash or unhashed_description:
raise Unsupported("description_hash")
raise UnsupportedError("description_hash")
r = await self.client.post(
"/v1/charges",

View file

@ -13,7 +13,7 @@ from .base import (
PaymentResponse,
PaymentStatus,
StatusResponse,
Unsupported,
UnsupportedError,
Wallet,
)
@ -65,7 +65,7 @@ class ZBDWallet(Wallet):
) -> InvoiceResponse:
# https://api.zebedee.io/v0/charges
if description_hash or unhashed_description:
raise Unsupported("description_hash")
raise UnsupportedError("description_hash")
msats_amount = amount * 1000
data: Dict = {

View file

@ -168,7 +168,8 @@ extend-exclude = [
# I - isort
# A - flake8-builtins
# C - mccabe
select = ["F", "E", "W", "I", "A", "C"]
# N - naming
select = ["F", "E", "W", "I", "A", "C", "N"]
ignore = []
# Allow autofix for all enabled rules (when `--fix`) is provided.
@ -178,6 +179,12 @@ unfixable = []
# Allow unused variables when underscore-prefixed.
dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
# needed for pydantic
[tool.ruff.lint.pep8-naming]
classmethod-decorators = [
"root_validator",
]
# Ignore unused imports in __init__.py files.
[tool.ruff.lint.extend-per-file-ignores]
"__init__.py" = ["F401", "F403"]

View file

@ -176,8 +176,8 @@ async def adminkey_headers_to(to_wallet):
@pytest_asyncio.fixture(scope="session")
async def invoice(to_wallet):
data = await get_random_invoice_data()
invoiceData = CreateInvoice(**data)
invoice = await api_payments_create_invoice(invoiceData, to_wallet)
invoice_data = CreateInvoice(**data)
invoice = await api_payments_create_invoice(invoice_data, to_wallet)
yield invoice
del invoice

View file

@ -10,7 +10,7 @@ from lnbits.core.services import fee_reserve_total
from lnbits.core.views.admin_api import api_auditor
from lnbits.core.views.payment_api import api_payment
from lnbits.settings import settings
from lnbits.wallets import get_wallet_class
from lnbits.wallets import get_funding_source
from ...helpers import (
cancel_invoice,
@ -22,7 +22,7 @@ from ...helpers import (
settle_invoice,
)
WALLET = get_wallet_class()
funding_source = get_funding_source()
# create account POST /api/v1/account
@ -407,7 +407,8 @@ async def test_api_payment_with_key(invoice, inkey_headers_from):
# check POST /api/v1/payments: invoice creation with a description hash
@pytest.mark.skipif(
WALLET.__class__.__name__ in ["CoreLightningWallet", "CoreLightningRestWallet"],
funding_source.__class__.__name__
in ["CoreLightningWallet", "CoreLightningRestWallet"],
reason="wallet does not support description_hash",
)
@pytest.mark.asyncio
@ -428,7 +429,7 @@ async def test_create_invoice_with_description_hash(client, inkey_headers_to):
@pytest.mark.skipif(
WALLET.__class__.__name__ in ["CoreLightningRestWallet"],
funding_source.__class__.__name__ in ["CoreLightningRestWallet"],
reason="wallet does not support unhashed_description",
)
@pytest.mark.asyncio
@ -540,8 +541,8 @@ async def test_pay_real_invoice(
payment_status = response.json()
assert payment_status["paid"]
WALLET = get_wallet_class()
status = await WALLET.get_payment_status(invoice["payment_hash"])
funding_source = get_funding_source()
status = await funding_source.get_payment_status(invoice["payment_hash"])
assert status.paid
await asyncio.sleep(1)
@ -571,7 +572,7 @@ async def test_create_real_invoice(client, adminkey_headers_from, inkey_headers_
async def listen():
found_checking_id = False
async for checking_id in get_wallet_class().paid_invoices_stream():
async for checking_id in get_funding_source().paid_invoices_stream():
if checking_id == invoice["checking_id"]:
found_checking_id = True
return
@ -622,8 +623,8 @@ async def test_pay_real_invoice_set_pending_and_check_state(
assert response["paid"]
# make sure that the backend also thinks it's paid
WALLET = get_wallet_class()
status = await WALLET.get_payment_status(invoice["payment_hash"])
funding_source = get_funding_source()
status = await funding_source.get_payment_status(invoice["payment_hash"])
assert status.paid
# get the outgoing payment from the db
@ -800,7 +801,7 @@ async def test_receive_real_invoice_set_pending_and_check_state(
async def listen():
found_checking_id = False
async for checking_id in get_wallet_class().paid_invoices_stream():
async for checking_id in get_funding_source().paid_invoices_stream():
if checking_id == invoice["checking_id"]:
found_checking_id = True
return

View file

@ -10,14 +10,15 @@ from lnbits.nodes.base import ChannelPoint, ChannelState, NodeChannel
from tests.conftest import pytest_asyncio, settings
from ...helpers import (
WALLET,
funding_source,
get_random_invoice_data,
get_unconnected_node_uri,
mine_blocks,
)
pytestmark = pytest.mark.skipif(
WALLET.__node_cls__ is None, reason="Cant test if node implementation isnt avilable"
funding_source.__node_cls__ is None,
reason="Cant test if node implementation isnt available",
)

View file

@ -14,7 +14,7 @@ from pydantic import BaseModel
from lnbits import core
from lnbits.db import DB_TYPE, POSTGRES, FromRowModel
from lnbits.wallets import get_wallet_class, set_wallet_class
from lnbits.wallets import get_funding_source, set_funding_source
class DbTestModel(FromRowModel):
@ -23,10 +23,10 @@ class DbTestModel(FromRowModel):
value: Optional[str] = None
def get_random_string(N: int = 10):
def get_random_string(iterations: int = 10):
return "".join(
random.SystemRandom().choice(string.ascii_uppercase + string.digits)
for _ in range(N)
for _ in range(iterations)
)
@ -34,9 +34,9 @@ async def get_random_invoice_data():
return {"out": False, "amount": 10, "memo": f"test_memo_{get_random_string(10)}"}
set_wallet_class()
WALLET = get_wallet_class()
is_fake: bool = WALLET.__class__.__name__ == "FakeWallet"
set_funding_source()
funding_source = get_funding_source()
is_fake: bool = funding_source.__class__.__name__ == "FakeWallet"
is_regtest: bool = not is_fake

View file

@ -131,39 +131,39 @@ def migrate_db(file: str, schema: str, exclude_tables: List[str] = []):
).fetchall()
for table in tables:
tableName = table[0]
print(f"Migrating table {tableName}")
table_name = table[0]
print(f"Migrating table {table_name}")
# hard coded skip for dbversions (already produced during startup)
if tableName == "dbversions":
if table_name == "dbversions":
continue
if exclude_tables and tableName in exclude_tables:
if exclude_tables and table_name in exclude_tables:
continue
columns = cursor.execute(f"PRAGMA table_info({tableName})").fetchall()
q = build_insert_query(schema, tableName, columns)
columns = cursor.execute(f"PRAGMA table_info({table_name})").fetchall()
q = build_insert_query(schema, table_name, columns)
data = cursor.execute(f"SELECT * FROM {tableName};").fetchall()
data = cursor.execute(f"SELECT * FROM {table_name};").fetchall()
if len(data) == 0:
print(f"🛑 You sneaky dev! Table {tableName} is empty!")
print(f"🛑 You sneaky dev! Table {table_name} is empty!")
insert_to_pg(q, data)
cursor.close()
def build_insert_query(schema, tableName, columns):
def build_insert_query(schema, table_name, columns):
to_columns = ", ".join([f'"{column[1].lower()}"' for column in columns])
values = ", ".join([to_column_type(column[2]) for column in columns])
return f"""
INSERT INTO {schema}.{tableName}({to_columns})
INSERT INTO {schema}.{table_name}({to_columns})
VALUES ({values});
"""
def to_column_type(columnType):
if columnType == "TIMESTAMP":
def to_column_type(column_type):
if column_type == "TIMESTAMP":
return "to_timestamp(%s)"
if columnType in ["BOOLEAN", "BOOL"]:
if column_type in ["BOOLEAN", "BOOL"]:
return "%s::boolean"
return "%s"