Skip to content
Merged
Show file tree
Hide file tree
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
5 changes: 3 additions & 2 deletions .github/workflows/pylint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.8", "3.9", "3.10"]
python-version: ["3.11"]
steps:
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
Expand All @@ -17,7 +17,8 @@ jobs:
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install pylint
pip install "pylint>=3.3"
pip install -e ".[dev]"
- name: Analysing the code with pylint
run: |
pylint $(git ls-files '*.py')
6 changes: 3 additions & 3 deletions .github/workflows/python-app.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@ jobs:

steps:
- uses: actions/checkout@v4
- name: Set up Python 3.10
- name: Set up Python 3.11
uses: actions/setup-python@v3
with:
python-version: "3.10"
python-version: "3.11"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install flake8 pytest
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
pip install -e ".[dev]"
- name: Lint with flake8
run: |
# stop the build if there are Python syntax errors or undefined names
Expand Down
61 changes: 61 additions & 0 deletions .pylintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
[MASTER]
# Use multiple processes to speed up Pylint.
jobs=1

[MESSAGES CONTROL]
disable=
# Style — already enforced by flake8/ruff
line-too-long,
wrong-import-order,
# Docstrings — not enforced in this project
missing-module-docstring,
missing-class-docstring,
missing-function-docstring,
# Design thresholds — adjusted below
too-few-public-methods,
too-many-arguments,
too-many-positional-arguments,
too-many-return-statements,
too-many-locals,
too-many-branches,
too-many-statements,
# Duplicate code — false positives in UI/template code
duplicate-code,
# Dict literal — cosmetic
use-dict-literal,
# Abstract method bodies — both pass and ... are fine
unnecessary-pass,
unnecessary-ellipsis,
# Broad exception catch is intentional in UI error handlers
broad-exception-caught,
# Lazy imports are an established pattern in this project (navigation, pdf services)
import-outside-toplevel,
# Design rules that are too strict for this codebase
too-many-instance-attributes,
too-many-lines,
too-many-nested-blocks,
# Cosmetic refactor suggestions
unnecessary-comprehension,
simplifiable-condition,
superfluous-parens,
# Naming conventions not followed in this project (D(), N_MAX, donate_url)
invalid-name,
disallowed-name,

[DESIGN]
max-args = 10
max-returns = 10
max-locals = 25
max-branches = 15
max-statements = 60

[FORMAT]
max-line-length = 127

[BASIC]
# Allow single-letter variable names in short scopes
good-names = i,j,k,n,e,f,s,t,x,y,_

[SIMILARITIES]
# Minimum lines number of a similarity.
min-similarity-lines = 10
1 change: 1 addition & 0 deletions __main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@


def main() -> None:
"""Entry point for the finance-tracker CLI."""
app()


Expand Down
21 changes: 10 additions & 11 deletions finance_tracker/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,16 +97,14 @@

import typer
from sqlmodel import Session, create_engine
from sqlmodel import SQLModel

from finance_tracker.config import DATABASE_URL, DOCS_DIR
from finance_tracker.domain.enums import ProductType, QuantityUnit, TransactionType
from finance_tracker.domain.models import Product, RateSchedule, Transaction, Valuation
from finance_tracker.domain.enums import TransactionType
from finance_tracker.domain.models import Transaction, Valuation
from finance_tracker.repositories.sqlmodel_repo import (
SQLModelProductRepository,
SQLModelTransactionRepository,
SQLModelValuationRepository,
SQLModelRateScheduleRepository,
init_db,
)
from finance_tracker.services.btc_price_service import BTCPriceService, BTCPriceServiceError
Expand Down Expand Up @@ -173,7 +171,8 @@ def init_db_cmd() -> None:
$ finance-tracker init-db
✅ Base de données initialisée
"""
init_db()
engine = create_engine(DATABASE_URL, echo=False)
init_db(engine)
typer.echo("✅ Base de données initialisée")


Expand Down Expand Up @@ -432,9 +431,9 @@ def add_transaction(product_name: str = typer.Option(..., help="Nom du produit")
if date:
try:
date_obj = datetime.fromisoformat(date)
except ValueError:
except ValueError as exc:
typer.echo("❌ Date invalide (format: YYYY-MM-DD)", err=True)
raise typer.Exit(1)
raise typer.Exit(1) from exc
else:
date_obj = datetime.utcnow()

Expand Down Expand Up @@ -518,9 +517,9 @@ def add_valuation(product_name: str = typer.Option(..., help="Nom du produit"),
if date:
try:
date_obj = datetime.fromisoformat(date)
except ValueError:
except ValueError as exc:
typer.echo("❌ Date invalide (format: YYYY-MM-DD)", err=True)
raise typer.Exit(1)
raise typer.Exit(1) from exc
else:
date_obj = datetime.utcnow()

Expand Down Expand Up @@ -736,9 +735,9 @@ def project(initial_amount: str = typer.Option(10000, help="Montant initial EUR"
# Validate frequency
try:
freq = ProjectionFrequency[frequency]
except KeyError:
except KeyError as exc:
typer.echo(f"❌ Fréquence invalide: {frequency}", err=True)
raise typer.Exit(1)
raise typer.Exit(1) from exc

# Create projection and calculate
projection = ProjectionResult(
Expand Down
2 changes: 1 addition & 1 deletion finance_tracker/domain/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from decimal import Decimal
from typing import Optional

from sqlmodel import Column, DateTime, Field, ForeignKey, Numeric, SQLModel
from sqlmodel import Column, DateTime, Field, Numeric, SQLModel

from .enums import ProductType, QuantityUnit, TransactionType

Expand Down
2 changes: 1 addition & 1 deletion finance_tracker/i18n/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def detect_language() -> str:
try:
accept_lang: str = st.context.headers.get("Accept-Language", "fr")
return "en" if accept_lang.lower().startswith("en") else "fr"
except Exception:
except (AttributeError, KeyError):
return "fr"


Expand Down
2 changes: 1 addition & 1 deletion finance_tracker/i18n/en.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"app.db_init_with_products": "✅ Database initialised with {n} default products",
"app.db_init": "✅ Database initialised",
"app.export_btn": "📥 Save database (PC)",
"app.no_db_warning": "Please import or create a database to get started.",
"app.sidebar_hint": "Open menu",
"app.nav_label": "Navigation",
"app.doc_link_btn": "📖 Documentation (README)",
"app.donate_btn": "☕ Buy me a Bitcoffee",
Expand Down
2 changes: 1 addition & 1 deletion finance_tracker/i18n/fr.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"app.db_init_with_products": "✅ Base initialisée avec {n} produits par défaut",
"app.db_init": "✅ Base initialisée",
"app.export_btn": "📥 Sauvegarder la base (PC)",
"app.no_db_warning": "Veuillez importer ou créer une base pour commencer.",
"app.sidebar_hint": "Ouvrir le menu",
"app.nav_label": "Navigation",
"app.doc_link_btn": "📖 Documentation (README)",
"app.donate_btn": "☕ Buy me a Bitcoffee",
Expand Down
40 changes: 20 additions & 20 deletions finance_tracker/repositories/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def create(self, product: Product) -> Product:
DuplicateProductError
If a product with the same name already exists.
"""
pass
...

@abstractmethod
def get_by_id(self, product_id: int) -> Optional[Product]:
Expand All @@ -44,7 +44,7 @@ def get_by_id(self, product_id: int) -> Optional[Product]:
Product or None
Product instance if found, None otherwise.
"""
pass
...

@abstractmethod
def get_by_name(self, name: str) -> Optional[Product]:
Expand All @@ -60,7 +60,7 @@ def get_by_name(self, name: str) -> Optional[Product]:
Product or None
Product instance if found, None otherwise.
"""
pass
...

@abstractmethod
def get_all(self) -> list[Product]:
Expand All @@ -71,7 +71,7 @@ def get_all(self) -> list[Product]:
list[Product]
List of all product instances.
"""
pass
...

@abstractmethod
def update(self, product: Product) -> Product:
Expand All @@ -92,7 +92,7 @@ def update(self, product: Product) -> Product:
ProductNotFoundError
If the product does not exist in the repository.
"""
pass
...

@abstractmethod
def delete(self, product_id: int) -> bool:
Expand All @@ -108,7 +108,7 @@ def delete(self, product_id: int) -> bool:
bool
True if deletion was successful, False otherwise.
"""
pass
...


class ITransactionRepository(ABC):
Expand All @@ -129,7 +129,7 @@ def create(self, transaction: Transaction) -> Transaction:
Transaction
The created transaction.
"""
pass
...

@abstractmethod
def get_by_id(self, transaction_id: int) -> Optional[Transaction]:
Expand All @@ -146,7 +146,7 @@ def get_by_id(self, transaction_id: int) -> Optional[Transaction]:
Optional[Transaction]
The transaction if found, None otherwise.
"""
pass
...

@abstractmethod
def get_by_product_id(self, product_id: int) -> list[Transaction]:
Expand All @@ -163,7 +163,7 @@ def get_by_product_id(self, product_id: int) -> list[Transaction]:
list[Transaction]
List of transactions associated with the product.
"""
pass
...

@abstractmethod
def get_all(self) -> list[Transaction]:
Expand All @@ -175,7 +175,7 @@ def get_all(self) -> list[Transaction]:
list[Transaction]
List of all transactions in the repository.
"""
pass
...

@abstractmethod
def get_all_by_type(self, transaction_type: TransactionType) -> list[Transaction]:
Expand All @@ -192,7 +192,7 @@ def get_all_by_type(self, transaction_type: TransactionType) -> list[Transaction
list[Transaction]
List of transactions matching the specified type.
"""
pass
...

@abstractmethod
def update(self, transaction: Transaction) -> Transaction:
Expand All @@ -209,7 +209,7 @@ def update(self, transaction: Transaction) -> Transaction:
Transaction
The updated transaction.
"""
pass
...

@abstractmethod
def delete(self, transaction_id: int) -> bool:
Expand All @@ -226,7 +226,7 @@ def delete(self, transaction_id: int) -> bool:
bool
True if the transaction was deleted, False otherwise.
"""
pass
...


class IValuationRepository(ABC):
Expand Down Expand Up @@ -254,7 +254,7 @@ def create(self, valuation: Valuation) -> Valuation:
ValidationError
If the valuation data is invalid.
"""
pass
...

@abstractmethod
def get_by_id(self, valuation_id: int) -> Optional[Valuation]:
Expand All @@ -270,7 +270,7 @@ def get_by_id(self, valuation_id: int) -> Optional[Valuation]:
Optional[Valuation]
The valuation if found, None otherwise.
"""
pass
...

@abstractmethod
def get_latest_by_product_id(self, product_id: int) -> Optional[Valuation]:
Expand All @@ -286,7 +286,7 @@ def get_latest_by_product_id(self, product_id: int) -> Optional[Valuation]:
Optional[Valuation]
The latest valuation for the product, None if none exists.
"""
pass
...

@abstractmethod
def get_by_product_id(self, product_id: int) -> list[Valuation]:
Expand All @@ -302,7 +302,7 @@ def get_by_product_id(self, product_id: int) -> list[Valuation]:
list[Valuation]
List of all valuations for the product, empty list if none found.
"""
pass
...

@abstractmethod
def get_all(self) -> list[Valuation]:
Expand All @@ -313,7 +313,7 @@ def get_all(self) -> list[Valuation]:
list[Valuation]
Complete list of all stored valuations.
"""
pass
...

@abstractmethod
def update(self, valuation: Valuation) -> Valuation:
Expand All @@ -334,7 +334,7 @@ def update(self, valuation: Valuation) -> Valuation:
ValidationError
If the updated data is invalid.
"""
pass
...

@abstractmethod
def delete(self, valuation_id: int) -> bool:
Expand All @@ -350,4 +350,4 @@ def delete(self, valuation_id: int) -> bool:
bool
True if deletion succeeded, False if valuation not found.
"""
pass
...
3 changes: 1 addition & 2 deletions finance_tracker/repositories/sqlmodel_repo.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@
from sqlalchemy import desc, select
from sqlmodel import Session, SQLModel

from finance_tracker.config import DATABASE_URL
from finance_tracker.domain.enums import ProductType, TransactionType
from finance_tracker.domain.enums import TransactionType
from finance_tracker.domain.models import Product, RateSchedule, Transaction, Valuation

from .base import IProductRepository, ITransactionRepository, IValuationRepository
Expand Down
Loading
Loading