2nd stage draft pydantic

This commit is contained in:
dni ⚡
2026-03-25 10:47:13 +01:00
parent 261350243f
commit b0b8ea95f2
33 changed files with 499 additions and 156 deletions
+80
View File
@@ -0,0 +1,80 @@
import pytest
from pydantic import ValidationError
from lnbits.core.models.extensions import InstallableExtension
from lnbits.core.models.lnurl import StoredPayLink
from lnbits.core.models.users import UserLabel
from lnbits.core.models.wallets import (
Wallet,
WalletPermission,
WalletSharePermission,
WalletShareStatus,
)
from lnbits.db import dict_to_model
def test_user_label_uses_pydantic_v2_pattern_validation():
label = UserLabel(name="label-1", color="#FF00AA")
assert label.name == "label-1"
assert label.color == "#FF00AA"
with pytest.raises(ValidationError):
UserLabel(name="label-1", color="bad-color")
def test_wallet_has_stored_paylinks_field_and_mirrors_it():
source_wallet = Wallet(
id="source-wallet-id",
user="source-user-id",
name="source",
adminkey="admin-key",
inkey="invoice-key",
)
source_wallet.stored_paylinks.links.append(
StoredPayLink(lnurl="lnurl1example", label="saved paylink")
)
shared_wallet = Wallet(
id="shared-wallet-id",
user="shared-user-id",
name="shared",
adminkey="shared-admin-key",
inkey="shared-invoice-key",
)
source_wallet.extra.shared_with.append(
WalletSharePermission(
request_id="share-request-id",
username="shared-user",
shared_with_wallet_id=shared_wallet.id,
permissions=[WalletPermission.VIEW_PAYMENTS],
status=WalletShareStatus.APPROVED,
)
)
shared_wallet.mirror_shared_wallet(source_wallet)
assert shared_wallet.stored_paylinks.links[0].lnurl == "lnurl1example"
assert shared_wallet.stored_paylinks.links[0].label == "saved paylink"
def test_db_dict_to_model_parses_optional_nested_pydantic_v2_models():
ext = dict_to_model(
{
"id": "ext-id",
"name": "Extension",
"version": "1.0.0",
"active": 1,
"meta": (
'{"installed_release": {"name": "Release", "version": "1.0.0", '
'"archive": "https://example.com/release.zip", '
'"source_repo": "lnbits/example"}, "payments": [], '
'"dependencies": [], "featured": false, '
'"has_paid_release": false, "has_free_release": false}'
),
},
InstallableExtension,
)
assert ext.meta is not None
assert ext.meta.installed_release is not None
assert ext.meta.installed_release.source_repo == "lnbits/example"
+59 -1
View File
@@ -1,6 +1,7 @@
import pytest
from pydantic import ValidationError
from lnbits.settings import RedirectPath
from lnbits.settings import EditableSettings, RedirectPath, Settings, UpdateSettings
lnurlp_redirect_path = {
"from_path": "/.well-known/lnurlp",
@@ -166,3 +167,60 @@ def test_redirect_path_new_path_from(lnurlp: RedirectPath):
lnurlp.new_path_from("/.well-known/lnurlp/path/more")
== "/lnurlp/api/v1/well-known/path/more"
)
def test_settings_loads_env_and_dotenv_values(tmp_path, monkeypatch):
env_file = tmp_path / ".env"
env_file.write_text(
"\n".join(
[
"lnbits_admin_users=alice,bob",
"STRIKE_API_ENDPOINT=https://dotenv.strike.example",
]
),
encoding="utf-8",
)
monkeypatch.chdir(tmp_path)
monkeypatch.setenv("LNBITS_ALLOWED_USERS", ' ["carol", "dave"] ')
monkeypatch.setenv("STRIKE_API_KEY", "secret-key")
monkeypatch.setenv("STRIKE_API_ENDPOINT", "https://env.strike.example")
settings = Settings()
assert settings.lnbits_admin_users == ["alice", "bob"]
assert settings.lnbits_allowed_users == ["carol", "dave"]
assert settings.strike_api_endpoint == "https://env.strike.example"
assert settings.strike_api_key == "secret-key"
def test_editable_settings_from_dict_ignores_unknown_fields():
editable_settings = EditableSettings.from_dict(
{"lnbits_admin_users": ["alice"], "unknown_setting": "ignored"}
)
assert editable_settings.lnbits_admin_users == ["alice"]
assert "unknown_setting" not in editable_settings.model_dump()
def test_update_settings_splits_string_lists_and_forbids_extra_fields():
updated = UpdateSettings.model_validate(
{
"lnbits_admin_users": "alice,bob",
"strike_api_endpoint": "https://api.strike.me/v1",
"strike_api_key": "secret-key",
}
)
assert updated.lnbits_admin_users == ["alice", "bob"]
assert updated.strike_api_endpoint == "https://api.strike.me/v1"
assert updated.strike_api_key == "secret-key"
with pytest.raises(ValidationError):
UpdateSettings.model_validate({"unknown_setting": True})
def test_update_settings_schema_does_not_include_env_names():
schema = UpdateSettings.model_json_schema()
assert "properties" in schema
assert all("env_names" not in prop for prop in schema["properties"].values())