Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: code quality #35

Merged
merged 4 commits into from
Aug 30, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: CI
on:
push:
branches:
- main
pull_request:

jobs:
lint:
uses: lnbits/lnbits/.github/workflows/lint.yml@dev
tests:
runs-on: ubuntu-latest
needs: [lint]
strategy:
matrix:
python-version: ['3.9', '3.10']
steps:
- uses: actions/checkout@v4
- uses: lnbits/lnbits/.github/actions/prepare@dev
with:
python-version: ${{ matrix.python-version }}
- name: Run pytest
uses: pavelzw/pytest-action@v2
env:
LNBITS_BACKEND_WALLET_CLASS: FakeWallet
PYTHONUNBUFFERED: 1
DEBUG: true
with:
verbose: true
job-summary: true
emoji: false
click-to-expand: true
custom-pytest: poetry run pytest
report-title: 'test (${{ matrix.python-version }})'
15 changes: 7 additions & 8 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
on:
push:
tags:
- "v[0-9]+.[0-9]+.[0-9]+"
- 'v[0-9]+.[0-9]+.[0-9]+'

jobs:

release:
runs-on: ubuntu-latest
steps:
@@ -34,12 +33,12 @@ jobs:
- name: Create pull request in extensions repo
env:
GH_TOKEN: ${{ secrets.EXT_GITHUB }}
repo_name: "${{ github.event.repository.name }}"
tag: "${{ github.ref_name }}"
branch: "update-${{ github.event.repository.name }}-${{ github.ref_name }}"
title: "[UPDATE] ${{ github.event.repository.name }} to ${{ github.ref_name }}"
body: "https://github.com/lnbits/${{ github.event.repository.name }}/releases/${{ github.ref_name }}"
archive: "https://github.com/lnbits/${{ github.event.repository.name }}/archive/refs/tags/${{ github.ref_name }}.zip"
repo_name: '${{ github.event.repository.name }}'
tag: '${{ github.ref_name }}'
branch: 'update-${{ github.event.repository.name }}-${{ github.ref_name }}'
title: '[UPDATE] ${{ github.event.repository.name }} to ${{ github.ref_name }}'
body: 'https://github.com/lnbits/${{ github.event.repository.name }}/releases/${{ github.ref_name }}'
archive: 'https://github.com/lnbits/${{ github.event.repository.name }}/archive/refs/tags/${{ github.ref_name }}.zip'
run: |
cd lnbits-extensions
git checkout -b $branch
131 changes: 3 additions & 128 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,129 +1,4 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
target/

# Jupyter Notebook
.ipynb_checkpoints

# IPython
profile_default/
ipython_config.py

# pyenv
.python-version

# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock

# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/

# Celery stuff
celerybeat-schedule
celerybeat.pid

# SageMath parsed files
*.sage.py

# Environments
.env
__pycache__
node_modules
.mypy_cache
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# Pyre type checker
.pyre/
12 changes: 12 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"semi": false,
"arrowParens": "avoid",
"insertPragma": false,
"printWidth": 80,
"proseWrap": "preserve",
"singleQuote": true,
"trailingComma": "none",
"useTabs": false,
"bracketSameLine": false,
"bracketSpacing": false
}
47 changes: 47 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
all: format check

format: prettier black ruff

check: mypy pyright checkblack checkruff checkprettier

prettier:
poetry run ./node_modules/.bin/prettier --write .
pyright:
poetry run ./node_modules/.bin/pyright

mypy:
poetry run mypy .

black:
poetry run black .

ruff:
poetry run ruff check . --fix

checkruff:
poetry run ruff check .

checkprettier:
poetry run ./node_modules/.bin/prettier --check .

checkblack:
poetry run black --check .

checkeditorconfig:
editorconfig-checker

test:
PYTHONUNBUFFERED=1 \
DEBUG=true \
poetry run pytest
install-pre-commit-hook:
@echo "Installing pre-commit hook to git"
@echo "Uninstall the hook with poetry run pre-commit uninstall"
poetry run pre-commit install

pre-commit:
poetry run pre-commit run --all-files


checkbundle:
@echo "skipping checkbundle"
4 changes: 2 additions & 2 deletions __init__.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from fastapi import APIRouter

from lnbits.db import Database
from .views_api import lndhub_api_router

from .views import lndhub_generic_router
from .views_api import lndhub_api_router

db = Database("ext_lndhub")
lndhub_ext: APIRouter = APIRouter(prefix="/lndhub", tags=["lndhub"])
5 changes: 2 additions & 3 deletions decorators.py
Original file line number Diff line number Diff line change
@@ -3,10 +3,9 @@
from fastapi import Request, status
from fastapi.param_functions import Security
from fastapi.security.api_key import APIKeyHeader
from starlette.exceptions import HTTPException

from lnbits.decorators import get_key_type
from lnbits.core.models import WalletTypeInfo
from lnbits.decorators import get_key_type
from starlette.exceptions import HTTPException

api_key_header_auth = APIKeyHeader(
name="Authorization",
59 changes: 59 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"name": "lndhub",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"prettier": "^3.2.5",
"pyright": "^1.1.358"
}
}
969 changes: 715 additions & 254 deletions poetry.lock

Large diffs are not rendered by default.

96 changes: 88 additions & 8 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,15 +1,95 @@
[tool.poetry]
name = "lndhub"
version = "0.5.0"
description = "LNbits LNDHub Extension"
authors = ["dni <office@dnilabs.com>"]
readme = "README.md"
name = "lnbits-lndhub"
version = "0.0.0"
description = "LNbits, free and open-source Lightning wallet and accounts system."
authors = ["Alan Bits <alan@lnbits.com>"]

[tool.poetry.dependencies]
python = "^3.9"
lnbits = "^0.12.7"
python = "^3.10 | ^3.9"
lnbits = "*"

[tool.poetry.group.dev.dependencies]
black = "^24.3.0"
pytest-asyncio = "^0.21.0"
pytest = "^7.3.2"
mypy = "^1.5.1"
pre-commit = "^3.2.2"
ruff = "^0.3.2"
pytest-md = "^0.2.0"

[build-system]
requires = ["poetry-core"]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"

[tool.mypy]
exclude = "(nostr/*)"
[[tool.mypy.overrides]]
module = [
"lnbits.*",
"lnurl.*",
"loguru.*",
"fastapi.*",
"pydantic.*",
"pyqrcode.*",
"shortuuid.*",
"httpx.*",
]
ignore_missing_imports = "True"

[tool.pytest.ini_options]
log_cli = false
testpaths = [
"tests"
]

[tool.black]
line-length = 88

[tool.ruff]
# Same as Black. + 10% rule of black
line-length = 88
exclude = [
"nostr",
]

[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
# B - bugbear
select = ["F", "E", "W", "I", "A", "C", "N", "UP", "RUF", "B"]
ignore = ["C901"]

# 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",
]

# Ignore unused imports in __init__.py files.
# [tool.ruff.lint.extend-per-file-ignores]
# "__init__.py" = ["F401", "F403"]

# [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",
]
Empty file added tests/__init__.py
Empty file.
11 changes: 11 additions & 0 deletions tests/test_init.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import pytest
from fastapi import APIRouter

from .. import lndhub_ext


# just import router and add it to a test router
@pytest.mark.asyncio
async def test_router():
router = APIRouter()
router.include_router(lndhub_ext)
2 changes: 1 addition & 1 deletion utils.py
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@


def to_buffer(payment_hash: str):
return {"type": "Buffer", "data": [b for b in bytes.fromhex(payment_hash)]}
return {"type": "Buffer", "data": list(bytes.fromhex(payment_hash))}


def decoded_as_lndhub(invoice: Bolt11):
6 changes: 4 additions & 2 deletions views.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
from fastapi import Depends, Request, APIRouter

from fastapi import APIRouter, Depends, Request
from lnbits.core.models import User
from lnbits.decorators import check_user_exists
from lnbits.helpers import template_renderer


def lndhub_renderer():
return template_renderer(["lndhub/templates"])


lndhub_generic_router = APIRouter()


@lndhub_generic_router.get("/")
async def lndhub_index(request: Request, user: User = Depends(check_user_exists)):
return lndhub_renderer().TemplateResponse(
53 changes: 27 additions & 26 deletions views_api.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import time
from base64 import urlsafe_b64encode

from fastapi import Depends, Query, APIRouter

from bolt11 import decode as bolt11_decode
from fastapi import APIRouter, Depends, Query
from lnbits.core.crud import get_payments
from lnbits.core.services import create_invoice, pay_invoice
from lnbits.core.models import WalletTypeInfo
from lnbits.core.services import create_invoice, pay_invoice
from lnbits.settings import settings

from .decorators import check_wallet, require_admin_key
from .models import LndhubAddInvoice, LndhubAuthData, LndhubCreateInvoice
from .utils import decoded_as_lndhub, to_buffer
from .models import LndhubAuthData, LndhubCreateInvoice, LndhubAddInvoice

lndhub_api_router = APIRouter(prefix="/ext")


@lndhub_api_router.get("/getinfo")
async def lndhub_getinfo():
return {"alias": settings.lnbits_site_title}
@@ -107,19 +107,21 @@ async def lndhub_gettxs(
"fee": payment.fee / 1000,
"value": int(payment.amount / 1000),
"timestamp": payment.time,
"memo": payment.extra.get("comment") or payment.memo if not payment.pending else "Payment in transition",
"memo": (
payment.extra.get("comment") or payment.memo
if not payment.pending
else "Payment in transition"
),
}
for payment in reversed(
(
await get_payments(
wallet_id=key_type.wallet.id,
pending=True,
complete=True,
outgoing=True,
incoming=False,
limit=limit,
offset=offset,
)
await get_payments(
wallet_id=key_type.wallet.id,
pending=True,
complete=True,
outgoing=True,
incoming=False,
limit=limit,
offset=offset,
)
)
]
@@ -138,23 +140,22 @@ async def lndhub_getuserinvoices(
"add_index": "500",
"description": payment.extra.get("comment") or payment.memo,
"payment_hash": payment.payment_hash,
"ispaid": payment.success,
# todo it works for lnbits 0.12.11 but not for 0.12.10
"ispaid": payment.success, # type: ignore
"amt": int(payment.amount / 1000),
"expire_time": int(time.time() + 1800),
"timestamp": payment.time,
"type": "user_invoice",
}
for payment in reversed(
(
await get_payments(
wallet_id=key_type.wallet.id,
pending=True,
complete=True,
incoming=True,
outgoing=False,
limit=limit,
offset=offset,
)
await get_payments(
wallet_id=key_type.wallet.id,
pending=True,
complete=True,
incoming=True,
outgoing=False,
limit=limit,
offset=offset,
)
)
]