mirror of
https://github.com/lnbits/lnbits-legend.git
synced 2025-03-15 12:20:21 +01:00
feat: adhere to ruff's B
rules (#2423)
* feat: adhere to ruff's `B` rules last of the ruff checks. closes #2308 * B904 * B008 * B005 * B025 * cleanup on fake
This commit is contained in:
parent
e13a37c193
commit
98ec59df96
28 changed files with 226 additions and 169 deletions
|
@ -137,8 +137,8 @@ def create_app() -> FastAPI:
|
|||
)
|
||||
|
||||
# Allow registering new extensions routes without direct access to the `app` object
|
||||
setattr(core_app_extra, "register_new_ext_routes", register_new_ext_routes(app))
|
||||
setattr(core_app_extra, "register_new_ratelimiter", register_new_ratelimiter(app))
|
||||
core_app_extra.register_new_ext_routes = register_new_ext_routes(app)
|
||||
core_app_extra.register_new_ratelimiter = register_new_ratelimiter(app)
|
||||
|
||||
# register static files
|
||||
static_path = Path("lnbits", "static")
|
||||
|
|
|
@ -18,11 +18,11 @@ async def migrate_extension_database(ext: Extension, current_version):
|
|||
try:
|
||||
ext_migrations = importlib.import_module(f"{ext.module_name}.migrations")
|
||||
ext_db = importlib.import_module(ext.module_name).db
|
||||
except ImportError as e:
|
||||
logger.error(e)
|
||||
except ImportError as exc:
|
||||
logger.error(exc)
|
||||
raise ImportError(
|
||||
f"Please make sure that the extension `{ext.code}` has a migrations file."
|
||||
)
|
||||
) from exc
|
||||
|
||||
async with ext_db.connect() as ext_conn:
|
||||
await run_migration(ext_conn, ext_migrations, ext.code, current_version)
|
||||
|
@ -113,7 +113,7 @@ def to_valid_user_id(user_id: str) -> UUID:
|
|||
raise ValueError("User ID must have at least 128 bits")
|
||||
try:
|
||||
int(user_id, 16)
|
||||
except Exception:
|
||||
raise ValueError("Invalid hex string for User ID.")
|
||||
except Exception as exc:
|
||||
raise ValueError("Invalid hex string for User ID.") from exc
|
||||
|
||||
return UUID(hex=user_id[:32], version=4)
|
||||
|
|
|
@ -201,8 +201,8 @@ async def pay_invoice(
|
|||
"""
|
||||
try:
|
||||
invoice = bolt11_decode(payment_request)
|
||||
except Exception:
|
||||
raise InvoiceError("Bolt11 decoding failed.")
|
||||
except Exception as exc:
|
||||
raise InvoiceError("Bolt11 decoding failed.") from exc
|
||||
|
||||
if not invoice.amount_msat or not invoice.amount_msat > 0:
|
||||
raise InvoiceError("Amountless invoices not supported.")
|
||||
|
@ -286,10 +286,10 @@ async def pay_invoice(
|
|||
conn=conn,
|
||||
**payment_kwargs,
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"could not create temporary payment: {e}")
|
||||
except Exception as exc:
|
||||
logger.error(f"could not create temporary payment: {exc}")
|
||||
# happens if the same wallet tries to pay an invoice twice
|
||||
raise PaymentError("Could not make payment.")
|
||||
raise PaymentError("Could not make payment.") from exc
|
||||
|
||||
# do the balance check
|
||||
wallet = await get_wallet(wallet_id, conn=conn)
|
||||
|
@ -727,7 +727,7 @@ def update_cached_settings(sets_dict: dict):
|
|||
except Exception:
|
||||
logger.warning(f"Failed overriding setting: {key}, value: {value}")
|
||||
if "super_user" in sets_dict:
|
||||
setattr(settings, "super_user", sets_dict["super_user"])
|
||||
settings.super_user = sets_dict["super_user"]
|
||||
|
||||
|
||||
async def init_admin_settings(super_user: Optional[str] = None) -> SuperSettings:
|
||||
|
|
|
@ -43,11 +43,11 @@ async def api_auditor():
|
|||
"node_balance_msats": int(node_balance),
|
||||
"lnbits_balance_msats": int(total_balance),
|
||||
}
|
||||
except Exception:
|
||||
except Exception as exc:
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
|
||||
detail="Could not audit balance.",
|
||||
)
|
||||
) from exc
|
||||
|
||||
|
||||
@admin_router.get(
|
||||
|
@ -113,10 +113,10 @@ async def api_restart_server() -> dict[str, str]:
|
|||
async def api_topup_balance(data: CreateTopup) -> dict[str, str]:
|
||||
try:
|
||||
await get_wallet(data.id)
|
||||
except Exception:
|
||||
except Exception as exc:
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.FORBIDDEN, detail="wallet does not exist."
|
||||
)
|
||||
) from exc
|
||||
|
||||
if settings.lnbits_backend_wallet_class == "VoidWallet":
|
||||
raise HTTPException(
|
||||
|
|
|
@ -79,7 +79,7 @@ async def api_lnurlscan(code: str, wallet: WalletTypeInfo = Depends(get_key_type
|
|||
try:
|
||||
url = str(lnurl_decode(code))
|
||||
domain = urlparse(url).netloc
|
||||
except Exception:
|
||||
except Exception as exc:
|
||||
# parse internet identifier (user@domain.com)
|
||||
name_domain = code.split("@")
|
||||
if len(name_domain) == 2 and len(name_domain[1].split(".")) >= 2:
|
||||
|
@ -94,7 +94,7 @@ async def api_lnurlscan(code: str, wallet: WalletTypeInfo = Depends(get_key_type
|
|||
else:
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.BAD_REQUEST, detail="invalid lnurl"
|
||||
)
|
||||
) from exc
|
||||
|
||||
# params is what will be returned to the client
|
||||
params: Dict = {"domain": domain}
|
||||
|
@ -119,14 +119,14 @@ async def api_lnurlscan(code: str, wallet: WalletTypeInfo = Depends(get_key_type
|
|||
|
||||
try:
|
||||
data = json.loads(r.text)
|
||||
except json.decoder.JSONDecodeError:
|
||||
except json.decoder.JSONDecodeError as exc:
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.SERVICE_UNAVAILABLE,
|
||||
detail={
|
||||
"domain": domain,
|
||||
"message": f"got invalid response '{r.text[:200]}'",
|
||||
},
|
||||
)
|
||||
) from exc
|
||||
|
||||
try:
|
||||
tag: str = data.get("tag")
|
||||
|
@ -185,7 +185,7 @@ async def api_lnurlscan(code: str, wallet: WalletTypeInfo = Depends(get_key_type
|
|||
"domain": domain,
|
||||
"message": f"lnurl JSON response invalid: {exc}",
|
||||
},
|
||||
)
|
||||
) from exc
|
||||
|
||||
return params
|
||||
|
||||
|
|
|
@ -68,11 +68,11 @@ async def login(data: LoginUsernamePassword) -> JSONResponse:
|
|||
raise HTTPException(HTTP_401_UNAUTHORIZED, "Invalid credentials.")
|
||||
|
||||
return _auth_success_response(user.username, user.id)
|
||||
except HTTPException as e:
|
||||
raise e
|
||||
except Exception as e:
|
||||
logger.debug(e)
|
||||
raise HTTPException(HTTP_500_INTERNAL_SERVER_ERROR, "Cannot login.")
|
||||
except HTTPException as exc:
|
||||
raise exc
|
||||
except Exception as exc:
|
||||
logger.debug(exc)
|
||||
raise HTTPException(HTTP_500_INTERNAL_SERVER_ERROR, "Cannot login.") from exc
|
||||
|
||||
|
||||
@auth_router.post("/usr", description="Login via the User ID")
|
||||
|
@ -86,11 +86,11 @@ async def login_usr(data: LoginUsr) -> JSONResponse:
|
|||
raise HTTPException(HTTP_401_UNAUTHORIZED, "User ID does not exist.")
|
||||
|
||||
return _auth_success_response(user.username or "", user.id)
|
||||
except HTTPException as e:
|
||||
raise e
|
||||
except Exception as e:
|
||||
logger.debug(e)
|
||||
raise HTTPException(HTTP_500_INTERNAL_SERVER_ERROR, "Cannot login.")
|
||||
except HTTPException as exc:
|
||||
raise exc
|
||||
except Exception as exc:
|
||||
logger.debug(exc)
|
||||
raise HTTPException(HTTP_500_INTERNAL_SERVER_ERROR, "Cannot login.") from exc
|
||||
|
||||
|
||||
@auth_router.get("/{provider}", description="SSO Provider")
|
||||
|
@ -124,16 +124,16 @@ async def handle_oauth_token(request: Request, provider: str) -> RedirectRespons
|
|||
user_id = decrypt_internal_message(provider_sso.state)
|
||||
request.session.pop("user", None)
|
||||
return await _handle_sso_login(userinfo, user_id)
|
||||
except HTTPException as e:
|
||||
raise e
|
||||
except ValueError as e:
|
||||
raise HTTPException(HTTP_403_FORBIDDEN, str(e))
|
||||
except Exception as e:
|
||||
logger.debug(e)
|
||||
except HTTPException as exc:
|
||||
raise exc
|
||||
except ValueError as exc:
|
||||
raise HTTPException(HTTP_403_FORBIDDEN, str(exc)) from exc
|
||||
except Exception as exc:
|
||||
logger.debug(exc)
|
||||
raise HTTPException(
|
||||
HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
f"Cannot authenticate user with {provider} Auth.",
|
||||
)
|
||||
) from exc
|
||||
|
||||
|
||||
@auth_router.post("/logout")
|
||||
|
@ -169,11 +169,13 @@ async def register(data: CreateUser) -> JSONResponse:
|
|||
user = await create_user(data)
|
||||
return _auth_success_response(user.username)
|
||||
|
||||
except ValueError as e:
|
||||
raise HTTPException(HTTP_403_FORBIDDEN, str(e))
|
||||
except Exception as e:
|
||||
logger.debug(e)
|
||||
raise HTTPException(HTTP_500_INTERNAL_SERVER_ERROR, "Cannot create user.")
|
||||
except ValueError as exc:
|
||||
raise HTTPException(HTTP_403_FORBIDDEN, str(exc)) from exc
|
||||
except Exception as exc:
|
||||
logger.debug(exc)
|
||||
raise HTTPException(
|
||||
HTTP_500_INTERNAL_SERVER_ERROR, "Cannot create user."
|
||||
) from exc
|
||||
|
||||
|
||||
@auth_router.put("/password")
|
||||
|
@ -189,13 +191,13 @@ async def update_password(
|
|||
|
||||
try:
|
||||
return await update_user_password(data)
|
||||
except AssertionError as e:
|
||||
raise HTTPException(HTTP_403_FORBIDDEN, str(e))
|
||||
except Exception as e:
|
||||
logger.debug(e)
|
||||
except AssertionError as exc:
|
||||
raise HTTPException(HTTP_403_FORBIDDEN, str(exc)) from exc
|
||||
except Exception as exc:
|
||||
logger.debug(exc)
|
||||
raise HTTPException(
|
||||
HTTP_500_INTERNAL_SERVER_ERROR, "Cannot update user password."
|
||||
)
|
||||
) from exc
|
||||
|
||||
|
||||
@auth_router.put("/update")
|
||||
|
@ -211,11 +213,13 @@ async def update(
|
|||
|
||||
try:
|
||||
return await update_account(user.id, data.username, None, data.config)
|
||||
except AssertionError as e:
|
||||
raise HTTPException(HTTP_403_FORBIDDEN, str(e))
|
||||
except Exception as e:
|
||||
logger.debug(e)
|
||||
raise HTTPException(HTTP_500_INTERNAL_SERVER_ERROR, "Cannot update user.")
|
||||
except AssertionError as exc:
|
||||
raise HTTPException(HTTP_403_FORBIDDEN, str(exc)) from exc
|
||||
except Exception as exc:
|
||||
logger.debug(exc)
|
||||
raise HTTPException(
|
||||
HTTP_500_INTERNAL_SERVER_ERROR, "Cannot update user."
|
||||
) from exc
|
||||
|
||||
|
||||
@auth_router.put("/first_install")
|
||||
|
@ -237,13 +241,13 @@ async def first_install(data: UpdateSuperuserPassword) -> JSONResponse:
|
|||
await update_user_password(super_user)
|
||||
settings.first_install = False
|
||||
return _auth_success_response(username=super_user.username)
|
||||
except AssertionError as e:
|
||||
raise HTTPException(HTTP_403_FORBIDDEN, str(e))
|
||||
except Exception as e:
|
||||
logger.debug(e)
|
||||
except AssertionError as exc:
|
||||
raise HTTPException(HTTP_403_FORBIDDEN, str(exc)) from exc
|
||||
except Exception as exc:
|
||||
logger.debug(exc)
|
||||
raise HTTPException(
|
||||
HTTP_500_INTERNAL_SERVER_ERROR, "Cannot update user password."
|
||||
)
|
||||
) from exc
|
||||
|
||||
|
||||
async def _handle_sso_login(userinfo: OpenID, verified_user_id: Optional[str] = None):
|
||||
|
|
|
@ -104,10 +104,10 @@ async def api_install_extension(
|
|||
ext_info.notify_upgrade()
|
||||
|
||||
return extension
|
||||
except AssertionError as e:
|
||||
raise HTTPException(HTTPStatus.BAD_REQUEST, str(e))
|
||||
except Exception as ex:
|
||||
logger.warning(ex)
|
||||
except AssertionError as exc:
|
||||
raise HTTPException(HTTPStatus.BAD_REQUEST, str(exc)) from exc
|
||||
except Exception as exc:
|
||||
logger.warning(exc)
|
||||
ext_info.clean_extension_files()
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
|
||||
|
@ -115,7 +115,7 @@ async def api_install_extension(
|
|||
f"Failed to install extension {ext_info.id} "
|
||||
f"({ext_info.installed_version})."
|
||||
),
|
||||
)
|
||||
) from exc
|
||||
|
||||
|
||||
@extension_router.delete("/{ext_id}")
|
||||
|
@ -159,10 +159,10 @@ async def api_uninstall_extension(
|
|||
await delete_installed_extension(ext_id=ext_info.id)
|
||||
|
||||
logger.success(f"Extension '{ext_id}' uninstalled.")
|
||||
except Exception as ex:
|
||||
except Exception as exc:
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail=str(ex)
|
||||
)
|
||||
status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail=str(exc)
|
||||
) from exc
|
||||
|
||||
|
||||
@extension_router.get("/{ext_id}/releases", dependencies=[Depends(check_admin)])
|
||||
|
@ -183,10 +183,10 @@ async def get_extension_releases(ext_id: str):
|
|||
|
||||
return extension_releases
|
||||
|
||||
except Exception as ex:
|
||||
except Exception as exc:
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail=str(ex)
|
||||
)
|
||||
status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail=str(exc)
|
||||
) from exc
|
||||
|
||||
|
||||
@extension_router.put("/invoice", dependencies=[Depends(check_admin)])
|
||||
|
@ -216,11 +216,13 @@ async def get_extension_invoice(data: CreateExtension):
|
|||
|
||||
return payment_info
|
||||
|
||||
except AssertionError as e:
|
||||
raise HTTPException(HTTPStatus.BAD_REQUEST, str(e))
|
||||
except Exception as ex:
|
||||
logger.warning(ex)
|
||||
raise HTTPException(HTTPStatus.INTERNAL_SERVER_ERROR, "Cannot request invoice")
|
||||
except AssertionError as exc:
|
||||
raise HTTPException(HTTPStatus.BAD_REQUEST, str(exc)) from exc
|
||||
except Exception as exc:
|
||||
logger.warning(exc)
|
||||
raise HTTPException(
|
||||
HTTPStatus.INTERNAL_SERVER_ERROR, "Cannot request invoice"
|
||||
) from exc
|
||||
|
||||
|
||||
@extension_router.get(
|
||||
|
@ -238,10 +240,10 @@ async def get_extension_release(org: str, repo: str, tag_name: str):
|
|||
"is_version_compatible": config.is_version_compatible(),
|
||||
"warning": config.warning,
|
||||
}
|
||||
except Exception as ex:
|
||||
except Exception as exc:
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail=str(ex)
|
||||
)
|
||||
status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail=str(exc)
|
||||
) from exc
|
||||
|
||||
|
||||
@extension_router.delete(
|
||||
|
@ -262,9 +264,9 @@ async def delete_extension_db(ext_id: str):
|
|||
except HTTPException as ex:
|
||||
logger.error(ex)
|
||||
raise ex
|
||||
except Exception as ex:
|
||||
logger.error(ex)
|
||||
except Exception as exc:
|
||||
logger.error(exc)
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
|
||||
detail=f"Cannot delete data for extension '{ext_id}'",
|
||||
)
|
||||
) from exc
|
||||
|
|
|
@ -171,9 +171,11 @@ async def extensions_install(
|
|||
"extensions": extensions,
|
||||
},
|
||||
)
|
||||
except Exception as e:
|
||||
logger.warning(e)
|
||||
raise HTTPException(status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail=str(e))
|
||||
except Exception as exc:
|
||||
logger.warning(exc)
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail=str(exc)
|
||||
) from exc
|
||||
|
||||
|
||||
@generic_router.get(
|
||||
|
@ -396,8 +398,10 @@ async def hex_to_uuid4(hex_value: str):
|
|||
try:
|
||||
user_id = to_valid_user_id(hex_value).hex
|
||||
return RedirectResponse(url=f"/wallet?usr={user_id}")
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, detail=str(e))
|
||||
except Exception as exc:
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.BAD_REQUEST, detail=str(exc)
|
||||
) from exc
|
||||
|
||||
|
||||
async def toggle_extension(extension_to_enable, extension_to_disable, user_id):
|
||||
|
|
|
@ -195,5 +195,7 @@ async def api_get_1ml_stats(node: Node = Depends(require_node)) -> Optional[Node
|
|||
try:
|
||||
r.raise_for_status()
|
||||
return r.json()["noderank"]
|
||||
except httpx.HTTPStatusError:
|
||||
raise HTTPException(status_code=404, detail="Node not found on 1ml.com")
|
||||
except httpx.HTTPStatusError as exc:
|
||||
raise HTTPException(
|
||||
status_code=404, detail="Node not found on 1ml.com"
|
||||
) from exc
|
||||
|
|
|
@ -13,6 +13,7 @@ from fastapi import (
|
|||
Depends,
|
||||
Header,
|
||||
HTTPException,
|
||||
Query,
|
||||
Request,
|
||||
)
|
||||
from fastapi.responses import JSONResponse
|
||||
|
@ -28,7 +29,6 @@ from lnbits.core.models import (
|
|||
Payment,
|
||||
PaymentFilters,
|
||||
PaymentHistoryPoint,
|
||||
Query,
|
||||
Wallet,
|
||||
WalletType,
|
||||
)
|
||||
|
@ -133,19 +133,19 @@ async def api_payments_create_invoice(data: CreateInvoice, wallet: Wallet):
|
|||
if data.description_hash:
|
||||
try:
|
||||
description_hash = bytes.fromhex(data.description_hash)
|
||||
except ValueError:
|
||||
except ValueError as exc:
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.BAD_REQUEST,
|
||||
detail="'description_hash' must be a valid hex string",
|
||||
)
|
||||
) from exc
|
||||
if data.unhashed_description:
|
||||
try:
|
||||
unhashed_description = bytes.fromhex(data.unhashed_description)
|
||||
except ValueError:
|
||||
except ValueError as exc:
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.BAD_REQUEST,
|
||||
detail="'unhashed_description' must be a valid hex string",
|
||||
)
|
||||
) from exc
|
||||
# do not save memo if description_hash or unhashed_description is set
|
||||
memo = ""
|
||||
|
||||
|
@ -170,8 +170,8 @@ 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 InvoiceError as e:
|
||||
raise HTTPException(status_code=520, detail=str(e))
|
||||
except InvoiceError as exc:
|
||||
raise HTTPException(status_code=520, detail=str(exc)) from exc
|
||||
except Exception as exc:
|
||||
raise exc
|
||||
|
||||
|
@ -192,12 +192,14 @@ async def api_payments_pay_invoice(
|
|||
payment_hash = await pay_invoice(
|
||||
wallet_id=wallet.id, payment_request=bolt11, extra=extra
|
||||
)
|
||||
except ValueError as e:
|
||||
raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, detail=str(e))
|
||||
except PermissionError as e:
|
||||
raise HTTPException(status_code=HTTPStatus.FORBIDDEN, detail=str(e))
|
||||
except PaymentError as e:
|
||||
raise HTTPException(status_code=520, detail=str(e))
|
||||
except ValueError as exc:
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.BAD_REQUEST, detail=str(exc)
|
||||
) from exc
|
||||
except PermissionError as exc:
|
||||
raise HTTPException(status_code=HTTPStatus.FORBIDDEN, detail=str(exc)) from exc
|
||||
except PaymentError as exc:
|
||||
raise HTTPException(status_code=520, detail=str(exc)) from exc
|
||||
except Exception as exc:
|
||||
raise exc
|
||||
|
||||
|
@ -282,11 +284,11 @@ async def api_payments_pay_lnurl(
|
|||
if r.is_error:
|
||||
raise httpx.ConnectError("LNURL callback connection error")
|
||||
r.raise_for_status()
|
||||
except (httpx.ConnectError, httpx.RequestError):
|
||||
except (httpx.ConnectError, httpx.RequestError) as exc:
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.BAD_REQUEST,
|
||||
detail=f"Failed to connect to {domain}.",
|
||||
)
|
||||
) from exc
|
||||
|
||||
params = json.loads(r.text)
|
||||
if params.get("status") == "ERROR":
|
||||
|
|
|
@ -27,10 +27,10 @@ async def api_public_payment_longpolling(payment_hash):
|
|||
invoice = bolt11.decode(payment.bolt11)
|
||||
if invoice.has_expired():
|
||||
return {"status": "expired"}
|
||||
except Exception:
|
||||
except Exception as exc:
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.BAD_REQUEST, detail="Invalid bolt11 invoice."
|
||||
)
|
||||
) from exc
|
||||
|
||||
payment_queue = asyncio.Queue(0)
|
||||
|
||||
|
|
|
@ -38,10 +38,10 @@ async def api_create_tinyurl(
|
|||
if tinyurl.wallet == wallet.wallet.id:
|
||||
return tinyurl
|
||||
return await create_tinyurl(url, endless, wallet.wallet.id)
|
||||
except Exception:
|
||||
except Exception as exc:
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.BAD_REQUEST, detail="Unable to create tinyurl"
|
||||
)
|
||||
) from exc
|
||||
|
||||
|
||||
@tinyurl_router.get(
|
||||
|
@ -60,10 +60,10 @@ async def api_get_tinyurl(
|
|||
raise HTTPException(
|
||||
status_code=HTTPStatus.FORBIDDEN, detail="Wrong key provided."
|
||||
)
|
||||
except Exception:
|
||||
except Exception as exc:
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.NOT_FOUND, detail="Unable to fetch tinyurl"
|
||||
)
|
||||
) from exc
|
||||
|
||||
|
||||
@tinyurl_router.delete(
|
||||
|
@ -83,10 +83,10 @@ async def api_delete_tinyurl(
|
|||
raise HTTPException(
|
||||
status_code=HTTPStatus.FORBIDDEN, detail="Wrong key provided."
|
||||
)
|
||||
except Exception:
|
||||
except Exception as exc:
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.BAD_REQUEST, detail="Unable to delete"
|
||||
)
|
||||
) from exc
|
||||
|
||||
|
||||
@tinyurl_router.get(
|
||||
|
|
|
@ -69,10 +69,10 @@ class KeyChecker(SecurityBase):
|
|||
detail="Invalid key or wallet.",
|
||||
)
|
||||
self.wallet = wallet
|
||||
except KeyError:
|
||||
except KeyError as exc:
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.BAD_REQUEST, detail="`X-API-KEY` header missing."
|
||||
)
|
||||
) from exc
|
||||
|
||||
|
||||
class WalletInvoiceKeyChecker(KeyChecker):
|
||||
|
@ -324,10 +324,10 @@ async def _get_account_from_token(access_token):
|
|||
return await get_account_by_email(str(payload.get("email")))
|
||||
|
||||
raise HTTPException(HTTPStatus.UNAUTHORIZED, "Data missing for access token.")
|
||||
except ExpiredSignatureError:
|
||||
except ExpiredSignatureError as exc:
|
||||
raise HTTPException(
|
||||
HTTPStatus.UNAUTHORIZED, "Session expired.", {"token-expired": "true"}
|
||||
)
|
||||
except JWTError as e:
|
||||
logger.debug(e)
|
||||
raise HTTPException(HTTPStatus.UNAUTHORIZED, "Invalid access token.")
|
||||
) from exc
|
||||
except JWTError as exc:
|
||||
logger.debug(exc)
|
||||
raise HTTPException(HTTPStatus.UNAUTHORIZED, "Invalid access token.") from exc
|
||||
|
|
|
@ -428,9 +428,9 @@ class InstallableExtension(BaseModel):
|
|||
|
||||
self._remember_payment_info()
|
||||
|
||||
except Exception as ex:
|
||||
logger.warning(ex)
|
||||
raise AssertionError("Cannot fetch extension archive file")
|
||||
except Exception as exc:
|
||||
logger.warning(exc)
|
||||
raise AssertionError("Cannot fetch extension archive file") from exc
|
||||
|
||||
archive_hash = file_hash(ext_zip_file)
|
||||
if self.installed_release.hash and self.installed_release.hash != archive_hash:
|
||||
|
@ -560,7 +560,11 @@ class InstallableExtension(BaseModel):
|
|||
return ext
|
||||
|
||||
@classmethod
|
||||
def from_rows(cls, rows: List[Any] = []) -> List["InstallableExtension"]:
|
||||
def from_rows(
|
||||
cls, rows: Optional[List[Any]] = None
|
||||
) -> List["InstallableExtension"]:
|
||||
if rows is None:
|
||||
rows = []
|
||||
return [InstallableExtension.from_row(row) for row in rows]
|
||||
|
||||
@classmethod
|
||||
|
|
|
@ -44,11 +44,12 @@ def catch_rpc_errors(f):
|
|||
async def wrapper(*args, **kwargs):
|
||||
try:
|
||||
return await f(*args, **kwargs)
|
||||
except RpcError as e:
|
||||
if e.error["code"] == -32602:
|
||||
raise HTTPException(status_code=400, detail=e.error["message"])
|
||||
except RpcError as exc:
|
||||
msg = exc.error["message"]
|
||||
if exc.error["code"] == -32602:
|
||||
raise HTTPException(status_code=400, detail=msg) from exc
|
||||
else:
|
||||
raise HTTPException(status_code=500, detail=e.error["message"])
|
||||
raise HTTPException(status_code=500, detail=msg) from exc
|
||||
|
||||
return wrapper
|
||||
|
||||
|
@ -66,9 +67,11 @@ class CoreLightningNode(Node):
|
|||
# https://docs.corelightning.org/reference/lightning-connect
|
||||
try:
|
||||
await self.ln_rpc("connect", uri)
|
||||
except RpcError as e:
|
||||
if e.error["code"] == 400:
|
||||
raise HTTPException(HTTPStatus.BAD_REQUEST, detail=e.error["message"])
|
||||
except RpcError as exc:
|
||||
if exc.error["code"] == 400:
|
||||
raise HTTPException(
|
||||
HTTPStatus.BAD_REQUEST, detail=exc.error["message"]
|
||||
) from exc
|
||||
else:
|
||||
raise
|
||||
|
||||
|
@ -76,12 +79,12 @@ class CoreLightningNode(Node):
|
|||
async def disconnect_peer(self, peer_id: str):
|
||||
try:
|
||||
await self.ln_rpc("disconnect", peer_id)
|
||||
except RpcError as e:
|
||||
if e.error["code"] == -1:
|
||||
except RpcError as exc:
|
||||
if exc.error["code"] == -1:
|
||||
raise HTTPException(
|
||||
HTTPStatus.BAD_REQUEST,
|
||||
detail=e.error["message"],
|
||||
)
|
||||
detail=exc.error["message"],
|
||||
) from exc
|
||||
else:
|
||||
raise
|
||||
|
||||
|
@ -105,14 +108,14 @@ class CoreLightningNode(Node):
|
|||
funding_txid=result["txid"],
|
||||
output_index=result["outnum"],
|
||||
)
|
||||
except RpcError as e:
|
||||
message = e.error["message"]
|
||||
except RpcError as exc:
|
||||
message = exc.error["message"]
|
||||
|
||||
if "amount: should be a satoshi amount" in message:
|
||||
raise HTTPException(
|
||||
HTTPStatus.BAD_REQUEST,
|
||||
detail="The amount is not a valid satoshi amount.",
|
||||
)
|
||||
) from exc
|
||||
|
||||
if "Unknown peer" in message:
|
||||
raise HTTPException(
|
||||
|
@ -121,7 +124,7 @@ class CoreLightningNode(Node):
|
|||
"We where able to connect to the peer but CLN "
|
||||
"can't find it when opening a channel."
|
||||
),
|
||||
)
|
||||
) from exc
|
||||
|
||||
if "Owning subdaemon openingd died" in message:
|
||||
# https://github.com/ElementsProject/lightning/issues/2798#issuecomment-511205719
|
||||
|
@ -131,14 +134,14 @@ class CoreLightningNode(Node):
|
|||
"Likely the peer didn't like our channel opening "
|
||||
"proposal and disconnected from us."
|
||||
),
|
||||
)
|
||||
) from exc
|
||||
|
||||
if (
|
||||
"Number of pending channels exceed maximum" in message
|
||||
or "exceeds maximum chan size of 10 BTC" in message
|
||||
or "Could not afford" in message
|
||||
):
|
||||
raise HTTPException(HTTPStatus.BAD_REQUEST, detail=message)
|
||||
raise HTTPException(HTTPStatus.BAD_REQUEST, detail=message) from exc
|
||||
raise
|
||||
|
||||
@catch_rpc_errors
|
||||
|
@ -152,13 +155,13 @@ class CoreLightningNode(Node):
|
|||
raise HTTPException(status_code=400, detail="Short id required")
|
||||
try:
|
||||
await self.ln_rpc("close", short_id)
|
||||
except RpcError as e:
|
||||
message = e.error["message"]
|
||||
except RpcError as exc:
|
||||
message = exc.error["message"]
|
||||
if (
|
||||
"Short channel ID not active:" in message
|
||||
or "Short channel ID not found" in message
|
||||
):
|
||||
raise HTTPException(HTTPStatus.BAD_REQUEST, detail=message)
|
||||
raise HTTPException(HTTPStatus.BAD_REQUEST, detail=message) from exc
|
||||
else:
|
||||
raise
|
||||
|
||||
|
|
|
@ -60,11 +60,13 @@ class LndRestNode(Node):
|
|||
)
|
||||
try:
|
||||
response.raise_for_status()
|
||||
except HTTPStatusError as e:
|
||||
json = e.response.json()
|
||||
except HTTPStatusError as exc:
|
||||
json = exc.response.json()
|
||||
if json:
|
||||
error = json.get("error") or json
|
||||
raise HTTPException(e.response.status_code, detail=error.get("message"))
|
||||
raise HTTPException(
|
||||
exc.response.status_code, detail=error.get("message")
|
||||
) from exc
|
||||
return response.json()
|
||||
|
||||
def get(self, path: str, **kwargs):
|
||||
|
@ -81,8 +83,8 @@ class LndRestNode(Node):
|
|||
async def connect_peer(self, uri: str):
|
||||
try:
|
||||
pubkey, host = uri.split("@")
|
||||
except ValueError:
|
||||
raise HTTPException(400, detail="Invalid peer URI")
|
||||
except ValueError as exc:
|
||||
raise HTTPException(400, detail="Invalid peer URI") from exc
|
||||
await self.request(
|
||||
"POST",
|
||||
"/v1/peers",
|
||||
|
@ -96,11 +98,11 @@ class LndRestNode(Node):
|
|||
async def disconnect_peer(self, peer_id: str):
|
||||
try:
|
||||
await self.request("DELETE", "/v1/peers/" + peer_id)
|
||||
except HTTPException as e:
|
||||
if "unable to disconnect" in e.detail:
|
||||
except HTTPException as exc:
|
||||
if "unable to disconnect" in exc.detail:
|
||||
raise HTTPException(
|
||||
HTTPStatus.BAD_REQUEST, detail="Peer is not connected"
|
||||
)
|
||||
) from exc
|
||||
raise
|
||||
|
||||
async def _get_peer_info(self, peer_id: str) -> NodePeerInfo:
|
||||
|
|
|
@ -48,18 +48,20 @@ def main(
|
|||
|
||||
# this beautiful beast parses all command line arguments and
|
||||
# passes them to the uvicorn server
|
||||
# TODO: why is this needed? it would be better only to rely on the commands options
|
||||
d = {}
|
||||
for a in ctx.args:
|
||||
item = a.split("=")
|
||||
if len(item) > 1: # argument like --key=value
|
||||
print(a, item)
|
||||
d[item[0].strip("--").replace("-", "_")] = (
|
||||
d[item[0].strip("--").replace("-", "_")] = ( # noqa: B005
|
||||
int(item[1]) # need to convert to int if it's a number
|
||||
if item[1].isdigit()
|
||||
else item[1]
|
||||
)
|
||||
else:
|
||||
d[a.strip("--")] = True # argument like --key
|
||||
# argument like --key
|
||||
d[a.strip("--")] = True # noqa: B005
|
||||
|
||||
while True:
|
||||
config = uvicorn.Config(
|
||||
|
|
|
@ -60,8 +60,8 @@ class AESCipher:
|
|||
aes = AES.new(key, AES.MODE_CBC, iv)
|
||||
try:
|
||||
return self.unpad(aes.decrypt(encrypted[16:])).decode() # type: ignore
|
||||
except UnicodeDecodeError:
|
||||
raise ValueError("Wrong passphrase")
|
||||
except UnicodeDecodeError as exc:
|
||||
raise ValueError("Wrong passphrase") from exc
|
||||
|
||||
def encrypt(self, message: bytes) -> str:
|
||||
passphrase = self.passphrase
|
||||
|
|
|
@ -93,11 +93,13 @@ class PaymentPendingStatus(PaymentStatus):
|
|||
|
||||
|
||||
class Wallet(ABC):
|
||||
async def cleanup(self):
|
||||
pass
|
||||
|
||||
__node_cls__: Optional[type[Node]] = None
|
||||
|
||||
@abstractmethod
|
||||
async def cleanup(self):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def status(self) -> Coroutine[None, None, StatusResponse]:
|
||||
pass
|
||||
|
|
|
@ -27,6 +27,9 @@ class ClicheWallet(Wallet):
|
|||
|
||||
self.endpoint = self.normalize_endpoint(settings.cliche_endpoint)
|
||||
|
||||
async def cleanup(self):
|
||||
pass
|
||||
|
||||
async def status(self) -> StatusResponse:
|
||||
try:
|
||||
ws = create_connection(self.endpoint)
|
||||
|
|
|
@ -31,6 +31,9 @@ async def run_sync(func) -> Any:
|
|||
class CoreLightningWallet(Wallet):
|
||||
__node_cls__ = CoreLightningNode
|
||||
|
||||
async def cleanup(self):
|
||||
pass
|
||||
|
||||
def __init__(self):
|
||||
rpc = settings.corelightning_rpc or settings.clightning_rpc
|
||||
if not rpc:
|
||||
|
|
|
@ -42,6 +42,9 @@ class FakeWallet(Wallet):
|
|||
32,
|
||||
).hex()
|
||||
|
||||
async def cleanup(self):
|
||||
pass
|
||||
|
||||
async def status(self) -> StatusResponse:
|
||||
logger.info(
|
||||
"FakeWallet funding source is for using LNbits as a centralised,"
|
||||
|
|
|
@ -109,6 +109,9 @@ class LndWallet(Wallet):
|
|||
def metadata_callback(self, _, callback):
|
||||
callback([("macaroon", self.macaroon)], None)
|
||||
|
||||
async def cleanup(self):
|
||||
pass
|
||||
|
||||
async def status(self) -> StatusResponse:
|
||||
try:
|
||||
resp = await self.rpc.ChannelBalance(ln.ChannelBalanceRequest())
|
||||
|
|
|
@ -77,12 +77,12 @@ class SparkWallet(Wallet):
|
|||
httpx.HTTPError,
|
||||
httpx.TimeoutException,
|
||||
) as exc:
|
||||
raise UnknownError(f"error connecting to spark: {exc}")
|
||||
raise UnknownError(f"error connecting to spark: {exc}") from exc
|
||||
|
||||
try:
|
||||
data = r.json()
|
||||
except Exception:
|
||||
raise UnknownError(r.text)
|
||||
except Exception as exc:
|
||||
raise UnknownError(r.text) from exc
|
||||
|
||||
if r.is_error:
|
||||
if r.status_code == 401:
|
||||
|
@ -171,7 +171,7 @@ class SparkWallet(Wallet):
|
|||
raise SparkError(
|
||||
f"listpays({payment_hash}) returned an unexpected response:"
|
||||
f" {listpays}"
|
||||
)
|
||||
) from exc
|
||||
|
||||
if pay["status"] == "failed":
|
||||
return PaymentResponse(False, None, None, None, str(exc))
|
||||
|
|
|
@ -13,6 +13,10 @@ from .base import (
|
|||
|
||||
|
||||
class VoidWallet(Wallet):
|
||||
|
||||
async def cleanup(self):
|
||||
pass
|
||||
|
||||
async def create_invoice(self, *_, **__) -> InvoiceResponse:
|
||||
return InvoiceResponse(
|
||||
ok=False, error_message="VoidWallet cannot create invoices."
|
||||
|
|
|
@ -181,7 +181,8 @@ extend-exclude = [
|
|||
# N - naming
|
||||
# UP - pyupgrade
|
||||
# RUF - ruff specific rules
|
||||
select = ["F", "E", "W", "I", "A", "C", "N", "UP", "RUF"]
|
||||
# B - bugbear
|
||||
select = ["F", "E", "W", "I", "A", "C", "N", "UP", "RUF", "B"]
|
||||
# UP007: pyupgrade: use X | Y instead of Optional. (python3.10)
|
||||
# RUF012: mutable-class-default
|
||||
ignore = ["UP007", "RUF012"]
|
||||
|
@ -206,3 +207,12 @@ classmethod-decorators = [
|
|||
[tool.ruff.lint.mccabe]
|
||||
# TODO: Decrease this to 10.
|
||||
max-complexity = 16
|
||||
|
||||
[tool.ruff.lint.flake8-bugbear]
|
||||
# Allow default arguments like, e.g., `data: List[str] = fastapi.Query(None)`.
|
||||
extend-immutable-calls = [
|
||||
"fastapi.Depends",
|
||||
"fastapi.Query",
|
||||
"fastapi.Body",
|
||||
"lnbits.decorators.parse_filters"
|
||||
]
|
||||
|
|
|
@ -62,7 +62,7 @@ def load_funding_source(funding_source: FundingSourceConfig) -> BaseWallet:
|
|||
custom_settings = funding_source.settings
|
||||
original_settings = {}
|
||||
|
||||
settings = getattr(wallets_module, "settings")
|
||||
settings = wallets_module.settings
|
||||
|
||||
for s in custom_settings:
|
||||
original_settings[s] = getattr(settings, s)
|
||||
|
@ -93,7 +93,7 @@ async def check_assertions(wallet, _test_data: WalletTest):
|
|||
elif "expect_error" in test_data:
|
||||
await _assert_error(wallet, tested_func, call_params, _test_data.expect_error)
|
||||
else:
|
||||
assert False, "Expected outcome not specified"
|
||||
raise AssertionError("Expected outcome not specified")
|
||||
|
||||
|
||||
async def _assert_data(wallet, tested_func, call_params, expect):
|
||||
|
|
|
@ -7,7 +7,7 @@ import argparse
|
|||
import os
|
||||
import sqlite3
|
||||
import sys
|
||||
from typing import List
|
||||
from typing import List, Optional
|
||||
|
||||
import psycopg2
|
||||
|
||||
|
@ -90,21 +90,23 @@ def insert_to_pg(query, data):
|
|||
for d in data:
|
||||
try:
|
||||
cursor.execute(query, d)
|
||||
except Exception as e:
|
||||
except Exception as exc:
|
||||
if args.ignore_errors:
|
||||
print(e)
|
||||
print(exc)
|
||||
print(f"Failed to insert {d}")
|
||||
else:
|
||||
print("query:", query)
|
||||
print("data:", d)
|
||||
raise ValueError(f"Failed to insert {d}")
|
||||
raise ValueError(f"Failed to insert {d}") from exc
|
||||
connection.commit()
|
||||
|
||||
cursor.close()
|
||||
connection.close()
|
||||
|
||||
|
||||
def migrate_core(file: str, exclude_tables: List[str] = []):
|
||||
def migrate_core(file: str, exclude_tables: Optional[List[str]] = None):
|
||||
if exclude_tables is None:
|
||||
exclude_tables = []
|
||||
print(f"Migrating core: {file}")
|
||||
migrate_db(file, "public", exclude_tables)
|
||||
print("✅ Migrated core")
|
||||
|
@ -118,8 +120,10 @@ def migrate_ext(file: str):
|
|||
print(f"✅ Migrated ext: {schema}")
|
||||
|
||||
|
||||
def migrate_db(file: str, schema: str, exclude_tables: List[str] = []):
|
||||
def migrate_db(file: str, schema: str, exclude_tables: Optional[List[str]] = None):
|
||||
# first we check if this file exists:
|
||||
if exclude_tables is None:
|
||||
exclude_tables = []
|
||||
assert os.path.isfile(file), f"{file} does not exist!"
|
||||
|
||||
cursor = get_sqlite_cursor(file)
|
||||
|
|
Loading…
Add table
Reference in a new issue