[project] name = "lnbits" version = "1.5.6" requires-python = ">=3.10,<3.13" description = "LNbits, free and open-source Lightning wallet and accounts system." authors = [{ name = "Alan Bits", email = "alan@lnbits.com" }] urls = { Homepage = "https://lnbits.com", Repository = "https://github.com/lnbits/lnbits" } readme = "README.md" dependencies = [ "bech32~=1.2.0", "click~=8.3.1", "fastapi~=0.116.1", "starlette~=0.47.1", "httpx~=0.27.2", "jinja2~=3.1.6", "lnurl~=0.10.0", "pydantic~=1.10.26", "pyqrcode~=1.2.1", "shortuuid~=1.0.13", "sse-starlette~=2.3.6", "typing-extensions~=4.15.0", "uvicorn~=0.40.0", "sqlalchemy~=1.4.54", "aiosqlite~=0.22.1", "asyncpg~=0.31.0", "uvloop~=0.22.1", "websockets~=15.0.1", "loguru~=0.7.3", "grpcio~=1.76.0", "protobuf~=6.33.5", "pyln-client~=25.12.0", "pywebpush~=2.2.0", "slowapi~=0.1.9", "websocket-client~=1.9.0", "pycryptodomex~=3.23.0", "packaging~=25.0.0", "bolt11~=2.1.1", "pyjwt~=2.12.0", "itsdangerous~=2.2.0", "fastapi-sso~=0.19.0", # needed for boltz, lnurldevice, watchonly extensions "embit~=0.8.0", # needed for scheduler extension "python-crontab~=3.3.0", "pynostr~=0.7.0", "python-multipart~=0.0.22", "filetype~=1.2.0", "nostr-sdk~=0.44.0", "bcrypt~=5.0.0", "jsonpath-ng~=1.7.0", "pillow~=12.1.0", "python-dotenv~=1.2.1", "greenlet~=3.3.0", "urllib3>=2.7.0", "pyinstrument>=5.1.2", "wasmtime>=45.0.0", ] [project.scripts] lnbits = "lnbits.server:main" lnbits-cli = "lnbits.commands:main" [project.optional-dependencies] breez = ["breez-sdk~=0.8.0", "breez-sdk-liquid~=0.11.11"] liquid = ["wallycore~=1.5.1", "boltz-client==0.4.0"] migration = ["psycopg2-binary~=2.9.11"] [dependency-groups] dev = [ "black~=26.3.1", "mypy~=1.17.1", "types-protobuf~=6.32.1.20251210", "pre-commit~=4.5.1", "openapi-spec-validator~=0.7.2", "ruff~=0.14.10", "types-passlib~=1.7.7.20250602", "openai~=2.14.0", "json5~=0.13.0", "asgi-lifespan~=2.1.0", "anyio~=4.12.1", "pytest~=9.0.2", "pytest-cov~=7.0.0", "pytest-md~=0.2.0", "pytest-httpserver~=1.1.3", "pytest-mock~=3.15.1", "types-mock~=5.2.0.20250924", "mock~=5.2.0", "grpcio-tools~=1.76.0", ] [tool.uv] exclude-newer = "1 week" [tool.poetry] packages = [ {include = "lnbits"}, {include = "lnbits/py.typed"}, ] [tool.pyright] include = [ "lnbits", "tests", "tools", ] exclude = [ "lnbits/wallets/boltz_grpc_files", "lnbits/wallets/lnd_grpc_files", "lnbits/extensions", "lnbits/upgrades", ] [tool.mypy] files = [ "lnbits", "tests", "tools", ] exclude = [ "^lnbits/wallets/boltz_grpc_files", "^lnbits/wallets/lnd_grpc_files", "^lnbits/extensions", "^lnbits/upgrades", ] plugins = "pydantic.mypy" [tool.pydantic-mypy] init_forbid_extra = true init_typed = true warn_required_dynamic_aliases = true warn_untyped_fields = true [[tool.mypy.overrides]] module = [ "embit.*", "secp256k1.*", "uvicorn.*", "sqlalchemy.*", "websocket.*", "websockets.*", "pyqrcode.*", "shortuuid.*", "grpc.*", "lnurl.*", "bolt11.*", "bitstring.*", "ecdsa.*", "pyngrok.*", "pynostr.*", "pyln.client.*", "py_vapid.*", "pywebpush.*", "fastapi_sso.sso.*", "json5.*", "jsonpath_ng.*", "filetype.*", "breez_sdk.*", "breez_sdk_liquid.*", ] ignore_missing_imports = "True" [tool.pytest.ini_options] log_cli = false addopts = "--durations=1 -s --cov=lnbits --cov-report=xml" testpaths = [ "tests" ] [tool.black] line-length = 88 # use upcoming new features # preview = true extend-exclude = """( lnbits/static | lnbits/extensions | lnbits/upgrades | lnbits/wallets/lnd_grpc_files | lnbits/wallets/boltz_grpc_files )""" [tool.ruff] # Same as Black. + 10% rule of black line-length = 88 # Exclude generated files. extend-exclude = [ "lnbits/wallets/lnd_grpc_files", "lnbits/wallets/boltz_grpc_files" ] [tool.ruff.lint] # Enable: # F - pyflakes # E - pycodestyle errors # W - pycodestyle warnings # I - isort # A - flake8-builtins # C - mccabe # N - naming # UP - pyupgrade # RUF - ruff specific rules # B - bugbear # S - bandit select = ["F", "E", "W", "I", "A", "C", "N", "UP", "RUF", "B", "S"] # UP007: pyupgrade: use X | Y instead of Optional. (python3.10) # RUF012: mutable-class-default # RUF043: pytest-raises-ambiguous-pattern (RUF043) ignore = ["RUF012", "RUF043"] # Allow autofix for all enabled rules (when `--fix`) is provided. fixable = ["ALL"] 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", "validator", ] [tool.ruff.lint.per-file-ignores] # S101: Use of assert detected. mostly for tests... # S105: Use of hard-coded password. mostly for tests... # S106: Possible hardcoded password: 'password'. # S307 Use of possibly insecure function; consider using `ast.literal_eval # S602 `subprocess` call with `shell=True` identified, security issue # S603 `subprocess` call: check for execution of untrusted input # S607: Starting a process with a partial executable path # S608: Possible SQL injection vector through string-based query construction # S324 Probable use of insecure hash functions in `hashlib`: `md5` # TODO: remove S101 ignore "lnbits/*" = ["S101"] "lnbits/core/views/admin_api.py" = ["S602", "S603", "S607"] "lnbits/core/services/extensions_builder.py" = ["S701"] "crypto.py" = ["S324"] "test*.py" = ["S101", "S105", "S106", "S307"] "tools*.py" = ["S101", "S608"] "tests/*" = ["S311"] "tests/regtest/helpers.py" = ["S603"] [tool.ruff.lint.mccabe] max-complexity = 10 [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" ] [build-system] requires = ["hatchling"] build-backend = "hatchling.build" [tool.hatch.build.targets.wheel] packages = ["lnbits"]