fix mypy + ruff linting

This commit is contained in:
Shroominic
2025-08-06 23:25:06 -03:00
parent 9ad4661111
commit eb5d832719
8 changed files with 81 additions and 75 deletions
+12 -3
View File
@@ -46,11 +46,20 @@ async def lifespan(_: FastAPI) -> AsyncGenerator[None, None]:
finally:
logger.info("Application shutdown initiated")
pricing_task.cancel()
payout_task.cancel()
if pricing_task is not None:
pricing_task.cancel()
if payout_task is not None:
payout_task.cancel()
try:
await asyncio.gather(pricing_task, payout_task, return_exceptions=True)
tasks_to_wait = []
if pricing_task is not None:
tasks_to_wait.append(pricing_task)
if payout_task is not None:
tasks_to_wait.append(payout_task)
if tasks_to_wait:
await asyncio.gather(*tasks_to_wait, return_exceptions=True)
logger.info("Background tasks stopped successfully")
except Exception as e:
logger.error(
+13 -22
View File
@@ -2,7 +2,7 @@ import asyncio
import json
import os
from typing import Any, AsyncGenerator, Callable, Dict, List, Optional, Tuple
from unittest.mock import AsyncMock, MagicMock, patch
from unittest.mock import MagicMock, patch
import pytest
import pytest_asyncio
@@ -61,8 +61,8 @@ else:
# Set test environment variables before importing the app
os.environ.update(test_env)
from router.core.db import ApiKey, get_session
from router.core.main import app, lifespan
from router.core.db import ApiKey, get_session # noqa: E402
from router.core.main import app, lifespan # noqa: E402
class TestmintWallet:
@@ -113,9 +113,10 @@ class TestmintWallet:
async def _create_real_token(self, amount: int) -> str:
"""Create real tokens using the testmint"""
from cashu.wallet.wallet import Wallet
import tempfile
from cashu.wallet.wallet import Wallet
logger.info(
f"Creating real token for {amount} sats from testmint {self.connection_url}"
)
@@ -155,10 +156,10 @@ class TestmintWallet:
async def _create_fallback_token(self, amount: int) -> str:
"""Fallback method to create a basic test token"""
import json
import base64
import time
import json
import random
import time
unique_id = int(time.time() * 1000000) + random.randint(1000, 9999)
token_data = {
@@ -198,7 +199,7 @@ class TestmintWallet:
token_base64 = token[6:] # Remove "cashuA" prefix
# Add padding if necessary
padding = (4 - len(token_base64) % 4) % 4
token_base64 += '=' * padding
token_base64 += "=" * padding
token_json = base64.urlsafe_b64decode(token_base64).decode()
token_data = json.loads(token_json)
@@ -247,7 +248,9 @@ class TestmintWallet:
# For testing, return a simulated balance
return 100000 # 100k sats
async def credit_balance(self, cashu_token: str, key: ApiKey, session) -> int:
async def credit_balance(
self, cashu_token: str, key: ApiKey, session: AsyncSession
) -> int:
"""Credit balance to API key - test implementation"""
try:
print(f"DEBUG: credit_balance called with token: {cashu_token[:20]}...")
@@ -449,7 +452,6 @@ async def integration_app(
if use_real_mint:
# Use real mint with sixty_nuts wallet
from .real_testmint import create_real_mint_wallet
# Use real mint - no wallet patches needed
with patch("router.core.db.engine", integration_engine):
@@ -660,15 +662,11 @@ async def background_tasks_controller() -> AsyncGenerator[Any, None]:
# Patch background task functions to respect controller
original_update_pricing: Optional[Callable] = None
original_check_refunds: Optional[Callable] = None
original_periodic_payout: Optional[Callable] = None
try:
from router.core.main import (
check_for_refunds,
periodic_payout,
update_sats_pricing,
)
from router.payment.models import update_sats_pricing
from router.wallet import periodic_payout
async def controlled_update_pricing() -> None:
while not controller.cancelled:
@@ -676,12 +674,6 @@ async def background_tasks_controller() -> AsyncGenerator[Any, None]:
await original_update_pricing()
await asyncio.sleep(1)
async def controlled_check_refunds() -> None:
while not controller.cancelled:
if not controller.paused and original_check_refunds:
await original_check_refunds()
await asyncio.sleep(1)
async def controlled_periodic_payout() -> None:
while not controller.cancelled:
if not controller.paused and original_periodic_payout:
@@ -690,7 +682,6 @@ async def background_tasks_controller() -> AsyncGenerator[Any, None]:
# Store originals and patch
original_update_pricing = update_sats_pricing
original_check_refunds = check_for_refunds
original_periodic_payout = periodic_payout
except ImportError:
+2 -5
View File
@@ -10,8 +10,8 @@ from unittest.mock import AsyncMock, patch
import pytest
from router.core.db import ApiKey
from router.wallet import periodic_payout
from router.payment.models import MODELS, Model, Pricing, update_sats_pricing
from router.wallet import periodic_payout
@pytest.mark.asyncio
@@ -456,7 +456,6 @@ class TestPeriodicPayoutTask:
# Mock wallet balance higher than user balances (indicating revenue)
wallet_balance = 200000 # 200 sats total
expected_revenue = wallet_balance - total_user_balance # 50 sats revenue
with (
patch("router.wallet.get_balance", AsyncMock(return_value=wallet_balance)),
@@ -704,9 +703,7 @@ class TestTaskInteractions:
"router.payment.models.update_sats_pricing",
lambda: task_with_cleanup("pricing"),
),
patch(
"router.wallet.periodic_payout", lambda: task_with_cleanup("refund")
),
patch("router.wallet.periodic_payout", lambda: task_with_cleanup("refund")),
patch("router.wallet.periodic_payout", lambda: task_with_cleanup("payout")),
):
# Start all tasks
+1 -1
View File
@@ -10,7 +10,7 @@ try:
from .real_testmint import create_real_mint_wallet
except ImportError:
# sixty_nuts not available, tests will be skipped
create_real_mint_wallet = None
create_real_mint_wallet = None # type: ignore
async def test_real_wallet() -> None:
@@ -224,9 +224,10 @@ async def test_malformed_authorization_header(integration_client: AsyncClient) -
response = await integration_client.get("/v1/wallet/")
# Should return 401 for invalid auth (not 400 in this implementation)
assert response.status_code in [400, 401], (
f"Malformed header '{auth_value[:20]}...' should fail"
)
assert response.status_code in [
400,
401,
], f"Malformed header '{auth_value[:20]}...' should fail"
@pytest.mark.integration
-1
View File
@@ -404,7 +404,6 @@ async def test_mint_unavailability_handling(
# The global mock in conftest.py is already in place,
# so we need to temporarily modify it
import router.wallet
from unittest.mock import patch
# Make the send_token method raise an exception
+6 -6
View File
@@ -5,30 +5,30 @@ from unittest.mock import Mock, patch
os.environ["UPSTREAM_BASE_URL"] = "http://test"
os.environ["UPSTREAM_API_KEY"] = "test"
from router.payment.helpers import get_max_cost_for_model
from router.payment.helpers import get_max_cost_for_model # noqa: E402
def test_get_max_cost_for_model_known():
def test_get_max_cost_for_model_known() -> None:
mock_model = Mock()
mock_model.id = "gpt-4"
mock_model.sats_pricing = Mock()
mock_model.sats_pricing.max_cost = 500
with patch("router.payment.helpers.MODELS", [mock_model]):
with patch("router.payment.helpers.MODEL_BASED_PRICING", True):
cost = get_max_cost_for_model("gpt-4")
assert cost == 500000 # 500 sats * 1000 = msats
def test_get_max_cost_for_model_unknown():
def test_get_max_cost_for_model_unknown() -> None:
with patch("router.payment.helpers.MODELS", []):
with patch("router.payment.helpers.COST_PER_REQUEST", 100):
cost = get_max_cost_for_model("unknown-model")
assert cost == 100
def test_get_max_cost_for_model_disabled():
def test_get_max_cost_for_model_disabled() -> None:
with patch("router.payment.helpers.MODEL_BASED_PRICING", False):
with patch("router.payment.helpers.COST_PER_REQUEST", 200):
cost = get_max_cost_for_model("any-model")
assert cost == 200
assert cost == 200
+43 -34
View File
@@ -8,32 +8,36 @@ from router.wallet import credit_balance, get_balance, recieve_token, send_token
@pytest.mark.asyncio
async def test_get_balance():
async def test_get_balance() -> None:
mock_wallet = Mock()
mock_wallet.available_balance = Mock(amount=50000)
mock_wallet.load_proofs = AsyncMock()
with patch("router.wallet.Wallet.with_db", return_value=mock_wallet):
balance = await get_balance("sat")
assert balance == 50000
@pytest.mark.asyncio
async def test_recieve_token_valid():
async def test_recieve_token_valid() -> None:
token_data = {
"token": [{
"mint": "http://mint:3338",
"proofs": [{"amount": 1000, "id": "test", "secret": "secret", "C": "curve"}]
}],
"unit": "sat"
"token": [
{
"mint": "http://mint:3338",
"proofs": [
{"amount": 1000, "id": "test", "secret": "secret", "C": "curve"}
],
}
],
"unit": "sat",
}
token_json = json.dumps(token_data)
token_b64 = base64.urlsafe_b64encode(token_json.encode()).decode()
token_str = f"cashuA{token_b64}"
mock_wallet = Mock()
mock_wallet.redeem = AsyncMock()
with patch("router.wallet.TRUSTED_MINTS", ["http://mint:3338"]):
with patch("router.wallet.deserialize_token_from_string") as mock_deserialize:
mock_token = Mock()
@@ -43,10 +47,10 @@ async def test_recieve_token_valid():
mock_token.amount = 1000
mock_token.proofs = [{"amount": 1000}]
mock_deserialize.return_value = mock_token
with patch("router.wallet.Wallet.with_db", return_value=mock_wallet):
mock_wallet.load_mint = AsyncMock()
amount, unit, mint = await recieve_token(token_str)
assert amount == 1000
assert unit == "sat"
@@ -54,9 +58,9 @@ async def test_recieve_token_valid():
@pytest.mark.asyncio
async def test_send_token():
async def test_send_token() -> None:
mock_wallet = Mock()
with patch("router.wallet.Wallet.with_db", return_value=mock_wallet):
with patch("router.wallet.send", return_value=(1000, "test_token")):
token = await send_token(1000, "sat", "http://mint:3338")
@@ -64,24 +68,24 @@ async def test_send_token():
@pytest.mark.asyncio
async def test_credit_balance():
async def test_credit_balance() -> None:
token_data = {
"token": [{
"mint": "http://mint:3338",
"proofs": [{"amount": 1000}]
}],
"unit": "sat"
"token": [{"mint": "http://mint:3338", "proofs": [{"amount": 1000}]}],
"unit": "sat",
}
token_json = json.dumps(token_data)
token_b64 = base64.urlsafe_b64encode(token_json.encode()).decode()
token_str = f"cashuA{token_b64}"
mock_key = Mock()
mock_key.balance = 5000000
mock_session = AsyncMock()
with patch("router.wallet.PRIMARY_MINT_URL", "http://mint:3338"):
with patch("router.wallet.recieve_token", return_value=(1000, "sat", "http://mint:3338")):
with patch(
"router.wallet.recieve_token",
return_value=(1000, "sat", "http://mint:3338"),
):
amount = await credit_balance(token_str, mock_key, mock_session)
assert amount == 1000000 # converted to msat
assert mock_key.balance == 6000000
@@ -89,32 +93,37 @@ async def test_credit_balance():
mock_session.commit.assert_called_once()
@pytest.mark.asyncio
async def test_credit_balance_invalid_mint():
@pytest.mark.asyncio
async def test_credit_balance_invalid_mint() -> None:
mock_key = Mock()
mock_session = AsyncMock()
with patch("router.wallet.recieve_token", return_value=(1000, "sat", "http://other:3338")):
with patch(
"router.wallet.recieve_token", return_value=(1000, "sat", "http://other:3338")
):
with pytest.raises(ValueError, match="Mint URL is not supported"):
await credit_balance("test_token", mock_key, mock_session)
@pytest.mark.asyncio
async def test_recieve_token_untrusted_mint():
async def test_recieve_token_untrusted_mint() -> None:
mock_wallet = Mock()
with patch("router.wallet.deserialize_token_from_string") as mock_deserialize:
mock_token = Mock()
mock_token.keysets = ["keyset1"]
mock_token.keysets = ["keyset1"]
mock_token.mint = "http://untrusted:3338"
mock_token.unit = "sat"
mock_token.amount = 1000
mock_deserialize.return_value = mock_token
with patch("router.wallet.Wallet.with_db", return_value=mock_wallet):
mock_wallet.load_mint = AsyncMock()
with patch("router.wallet.swap_to_primary_mint", return_value=(900, "sat", "http://mint:3338")):
with patch(
"router.wallet.swap_to_primary_mint",
return_value=(900, "sat", "http://mint:3338"),
):
amount, unit, mint = await recieve_token("test_token")
assert amount == 900
assert unit == "sat"
assert mint == "http://mint:3338"
assert unit == "sat"
assert mint == "http://mint:3338"