feat: Add mypy to pre-commit.

This commit is contained in:
Elisiário Couto
2025-09-03 21:40:15 +01:00
committed by Elisiário Couto
parent de3da84dff
commit ec8ef8346a
34 changed files with 226 additions and 242 deletions

0
leggen/__init__.py Normal file
View File

View File

@@ -1,6 +1,6 @@
import os
import requests
from typing import Dict, Any, Optional, List
from typing import Dict, Any, Optional, List, Union
from urllib.parse import urljoin
from leggen.utils.text import error
@@ -9,9 +9,13 @@ from leggen.utils.text import error
class LeggendAPIClient:
"""Client for communicating with the leggend FastAPI service"""
base_url: str
def __init__(self, base_url: Optional[str] = None):
self.base_url = base_url or os.environ.get(
"LEGGEND_API_URL", "http://localhost:8000"
self.base_url = (
base_url
or os.environ.get("LEGGEND_API_URL", "http://localhost:8000")
or "http://localhost:8000"
)
self.session = requests.Session()
self.session.headers.update(
@@ -36,7 +40,7 @@ class LeggendAPIClient:
try:
error_data = response.json()
error(f"Error details: {error_data.get('detail', 'Unknown error')}")
except:
except Exception:
error(f"Response: {response.text}")
raise
except Exception as e:
@@ -48,7 +52,7 @@ class LeggendAPIClient:
try:
response = self._make_request("GET", "/health")
return response.get("status") == "healthy"
except:
except Exception:
return False
# Bank endpoints
@@ -122,7 +126,7 @@ class LeggendAPIClient:
self, days: int = 30, account_id: Optional[str] = None
) -> Dict[str, Any]:
"""Get transaction statistics"""
params = {"days": days}
params: Dict[str, Union[int, str]] = {"days": days}
if account_id:
params["account_id"] = account_id
@@ -141,7 +145,7 @@ class LeggendAPIClient:
self, account_ids: Optional[List[str]] = None, force: bool = False
) -> Dict[str, Any]:
"""Trigger a sync"""
data = {"force": force}
data: Dict[str, Union[bool, List[str]]] = {"force": force}
if account_ids:
data["account_ids"] = account_ids
@@ -152,7 +156,7 @@ class LeggendAPIClient:
self, account_ids: Optional[List[str]] = None, force: bool = False
) -> Dict[str, Any]:
"""Run sync synchronously"""
data = {"force": force}
data: Dict[str, Union[bool, List[str]]] = {"force": force}
if account_ids:
data["account_ids"] = account_ids
@@ -172,7 +176,11 @@ class LeggendAPIClient:
cron: Optional[str] = None,
) -> Dict[str, Any]:
"""Update scheduler configuration"""
data = {"enabled": enabled, "hour": hour, "minute": minute}
data: Dict[str, Union[bool, int, str]] = {
"enabled": enabled,
"hour": hour,
"minute": minute,
}
if cron:
data["cron"] = cron

View File

@@ -68,7 +68,7 @@ def add(ctx):
success("Bank connection request created successfully!")
warning(
f"Please open the following URL in your browser to complete the authorization:"
"Please open the following URL in your browser to complete the authorization:"
)
click.echo(f"\n{result['link']}\n")

View File

@@ -1,7 +1,6 @@
import click
from leggen.main import cli
from leggen.utils.network import delete as http_delete
from leggen.utils.text import info, success
@@ -16,11 +15,12 @@ def delete(ctx, requisition_id: str):
Check `leggen status` to get the REQUISITION_ID
"""
import requests
info(f"Deleting Bank Requisition: {requisition_id}")
_ = http_delete(
ctx,
f"/requisitions/{requisition_id}",
)
api_url = ctx.obj.get("api_url", "http://localhost:8000")
res = requests.delete(f"{api_url}/requisitions/{requisition_id}")
res.raise_for_status()
success(f"Bank Requisition {requisition_id} deleted")

View File

@@ -27,7 +27,7 @@ def sync(ctx: click.Context, wait: bool, force: bool):
result = api_client.sync_now(force=force)
if result.get("success"):
success(f"Sync completed successfully!")
success("Sync completed successfully!")
info(f"Accounts processed: {result.get('accounts_processed', 0)}")
info(f"Transactions added: {result.get('transactions_added', 0)}")
info(f"Balances updated: {result.get('balances_updated', 0)}")

View File

@@ -5,7 +5,6 @@ from pathlib import Path
import click
from leggen.utils.auth import get_token
from leggen.utils.config import load_config
from leggen.utils.text import error
@@ -111,14 +110,4 @@ def cli(ctx: click.Context, api_url: str):
return
# Store API URL in context for commands to use
if api_url:
ctx.obj["api_url"] = api_url
# For backwards compatibility, still support direct GoCardless calls
# This will be used as fallback if leggend service is not available
try:
token = get_token(ctx)
ctx.obj["headers"] = {"Authorization": f"Bearer {token}"}
except Exception:
# If we can't get token, commands will rely on API service
pass
ctx.obj["api_url"] = api_url

View File

@@ -1,62 +0,0 @@
import json
from pathlib import Path
import click
import requests
from leggen.utils.text import warning
def create_token(ctx: click.Context) -> str:
"""
Create a new token
"""
res = requests.post(
f"{ctx.obj['gocardless']['url']}/token/new/",
json={
"secret_id": ctx.obj["gocardless"]["key"],
"secret_key": ctx.obj["gocardless"]["secret"],
},
)
res.raise_for_status()
auth = res.json()
save_auth(auth)
return auth["access"]
def get_token(ctx: click.Context) -> str:
"""
Get the token from the auth file or request a new one
"""
auth_file = Path.home() / ".config" / "leggen" / "auth.json"
if auth_file.exists():
with click.open_file(str(auth_file), "r") as f:
auth = json.load(f)
if not auth.get("access"):
return create_token(ctx)
res = requests.post(
f"{ctx.obj['gocardless']['url']}/token/refresh/",
json={"refresh": auth["refresh"]},
)
try:
res.raise_for_status()
auth.update(res.json())
save_auth(auth)
return auth["access"]
except requests.exceptions.HTTPError:
warning(
f"Token probably expired, requesting a new one.\nResponse: {res.status_code}\n{res.text}"
)
return create_token(ctx)
else:
return create_token(ctx)
def save_auth(d: dict):
auth_dir = Path.home() / ".config" / "leggen"
auth_dir.mkdir(parents=True, exist_ok=True)
auth_file = auth_dir / "auth.json"
with click.open_file(str(auth_file), "w") as f:
json.dump(d, f)

View File

@@ -3,7 +3,6 @@ from datetime import datetime
import click
import leggen.database.sqlite as sqlite_engine
from leggen.utils.network import get
from leggen.utils.text import info, warning
@@ -32,15 +31,21 @@ def persist_transactions(ctx: click.Context, account: str, transactions: list) -
def save_transactions(ctx: click.Context, account: str) -> list:
import requests
api_url = ctx.obj.get("api_url", "http://localhost:8000")
info(f"[{account}] Getting account details")
account_info = get(ctx, f"/accounts/{account}")
res = requests.get(f"{api_url}/accounts/{account}")
res.raise_for_status()
account_info = res.json()
info(f"[{account}] Getting transactions")
transactions = []
account_transactions = get(ctx, f"/accounts/{account}/transactions/").get(
"transactions", []
)
res = requests.get(f"{api_url}/accounts/{account}/transactions/")
res.raise_for_status()
account_transactions = res.json().get("transactions", [])
for transaction in account_transactions.get("booked", []):
booked_date = transaction.get("bookingDateTime") or transaction.get(

View File

@@ -1,64 +0,0 @@
import click
import requests
from leggen.utils.text import error
def get(ctx: click.Context, path: str, params: dict = {}):
"""
GET request to the GoCardless API
"""
url = f"{ctx.obj['gocardless']['url']}{path}"
res = requests.get(url, headers=ctx.obj["headers"], params=params)
try:
res.raise_for_status()
except Exception as e:
error(f"Error: {e}\n{res.text}")
ctx.abort()
return res.json()
def post(ctx: click.Context, path: str, data: dict = {}):
"""
POST request to the GoCardless API
"""
url = f"{ctx.obj['gocardless']['url']}{path}"
res = requests.post(url, headers=ctx.obj["headers"], json=data)
try:
res.raise_for_status()
except Exception as e:
error(f"Error: {e}\n{res.text}")
ctx.abort()
return res.json()
def put(ctx: click.Context, path: str, data: dict = {}):
"""
PUT request to the GoCardless API
"""
url = f"{ctx.obj['gocardless']['url']}{path}"
res = requests.put(url, headers=ctx.obj["headers"], json=data)
try:
res.raise_for_status()
except Exception as e:
error(f"Error: {e}\n{res.text}")
ctx.abort()
return res.json()
def delete(ctx: click.Context, path: str):
"""
DELETE request to the GoCardless API
"""
url = f"{ctx.obj['gocardless']['url']}{path}"
res = requests.delete(url, headers=ctx.obj["headers"])
try:
res.raise_for_status()
except Exception as e:
error(f"Error: {e}\n{res.text}")
ctx.abort()
return res.json()