From 41679d18612749501f7e844fdc3cbb97286a6f6c Mon Sep 17 00:00:00 2001 From: Antoine Van Elstraete Date: Wed, 11 Mar 2026 16:23:39 +0100 Subject: [PATCH] feat: initial Flask project setup with factory pattern --- app/__init__.py | 39 ++++++++++++ app/__pycache__/__init__.cpython-314.pyc | Bin 0 -> 2401 bytes app/routes/__init__.py | 0 .../__pycache__/__init__.cpython-314.pyc | Bin 0 -> 167 bytes .../__pycache__/dashboard.cpython-314.pyc | Bin 0 -> 265 bytes .../__pycache__/entries.cpython-314.pyc | Bin 0 -> 261 bytes .../__pycache__/reports.cpython-314.pyc | Bin 0 -> 261 bytes app/routes/dashboard.py | 3 + app/routes/entries.py | 3 + app/routes/reports.py | 3 + requirements.txt | 5 ++ run.py | 6 ++ tests/conftest.py | 60 ++++++++++++++++++ 13 files changed, 119 insertions(+) create mode 100644 app/__init__.py create mode 100644 app/__pycache__/__init__.cpython-314.pyc create mode 100644 app/routes/__init__.py create mode 100644 app/routes/__pycache__/__init__.cpython-314.pyc create mode 100644 app/routes/__pycache__/dashboard.cpython-314.pyc create mode 100644 app/routes/__pycache__/entries.cpython-314.pyc create mode 100644 app/routes/__pycache__/reports.cpython-314.pyc create mode 100644 app/routes/dashboard.py create mode 100644 app/routes/entries.py create mode 100644 app/routes/reports.py create mode 100644 requirements.txt create mode 100644 run.py create mode 100644 tests/conftest.py diff --git a/app/__init__.py b/app/__init__.py new file mode 100644 index 0000000..b9200be --- /dev/null +++ b/app/__init__.py @@ -0,0 +1,39 @@ +from flask import Flask +from flask_sqlalchemy import SQLAlchemy +import tomllib +import os + +db = SQLAlchemy() + + +def create_app(config_path=None): + app = Flask(__name__, instance_relative_config=True) + + os.makedirs(app.instance_path, exist_ok=True) + + app.config["SQLALCHEMY_DATABASE_URI"] = f"sqlite:///{os.path.join(app.instance_path, 'worklog.db')}" + app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False + app.config["SECRET_KEY"] = os.environ.get("SECRET_KEY", "dev-secret-change-in-prod") + + # Load TOML config + if config_path is None: + config_path = os.path.join(os.path.dirname(app.root_path), "config.toml") + if os.path.exists(config_path): + with open(config_path, "rb") as f: + app.config["TOML"] = tomllib.load(f) + else: + app.config["TOML"] = {} + + db.init_app(app) + + from app.routes.dashboard import bp as dashboard_bp + from app.routes.entries import bp as entries_bp + from app.routes.reports import bp as reports_bp + app.register_blueprint(dashboard_bp) + app.register_blueprint(entries_bp) + app.register_blueprint(reports_bp) + + with app.app_context(): + db.create_all() + + return app diff --git a/app/__pycache__/__init__.cpython-314.pyc b/app/__pycache__/__init__.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..18f3f04537ec41ccde3e51e6a6f098392b74623a GIT binary patch literal 2401 zcma)8TTB#J7(TNzduMm4HxySEgsL0dT`#0qks9REU2fvI#hTDgW_J(ElwoH&GoX@& zK${duOu(dxnm!oYCek;3YD}8wLlgVR3Knz3#HQ^-pK4-K6QBB@-5nOXQhRpiod5jS z@BhzbrrzsuA!vVnc}M!1L+Cd;F`K18yyyU85`Bz#CWfMn!2~F6iCLno!RBZ-#u*&& z*qGI@e#F+GhJvYK(8^K2~&+Ww@HAVaJjvZxOO;W~S!yG2e8;gL(dNv2>& z2Rl40JTKY+*d!WQlMR@_5D$)upQAW8Dez%2eFPwdbzX9% zG4=9epJ(Ho&NlJOH58DQp(7U1@s?Wh)_uU_ZJS8#RJsmNd8voKt))EP!8^^^n|O9m z&;4jHijaSOg#VfGI!v##*j|bWaO^1MHWb#BcbjZKofLz45wr z&*=|T=M zb`O%6|JI6wpS)hs7l-?1rY4pOyF66af5yM&(8ZLyA6 zYfC(Ky7w&HbM38sdtB&hKR>=Jg~viVPHNZ)C5OaJ8i%AzNY#{7@3=dUCTu7pGO=h0 z!o^SbbOSg`LJjWH=pBN>9Is$?5< zVNDq|upUl{`cOg*2fpmiI-+E+~*X^spjBRC>v z3@8nbz-mMcF(G4dG?c=jgrcSBVuVaNgoy}3E^8sIUMfOTRqY^nb;6_TaF`Hk}w!CJc?GbnQS@_tGTkcidt+?mE>%X5|={T3|IJbBn zFTFdscr3kmaA>l1x^t>?(RU!r1s@*;FZpRC%N<$`)Z7@qK7M23`ow~~c;ehr;KRIl z=Cds4e{MsLtq<*$t2=gHOr+nrpRrL%z=bClRzms)T=2D%4RF}DJe{hXYxufuZ%-L7C$}CrT?Zh&7 zpg23e%g3(N*qoRyE9m8%ZdoM+Z^*$2T~yCG7UZ?f}cEd&N^uU`6r`HQo% zz<;IhgyR1cu6w`9`oOa{*-a!1|HpS|vAz!_wEgAQUHq@No3lT)6f1vuSe{+mOi z9}OCPQ)oWg?V%lA)bG&?=#f?r9dVo(QBtEaeov!!7=3H$RPi~>Fw9d_@f7WUg1k?V V^H;0yi-AeY-?l2oryT-~e*mu4>P{wCAAftgHh(Vb_lhJP_LlF~@{~08C%SAsUKQ~oB zF|Q;)GcQ#?CACbyBrz!`HL+ATB~>>mzbHkwpeSD#CZAYPpkI_2KczG$)vkyYXeh|qVi4mKGb1Bo5i^hl05-rWBme*a literal 0 HcmV?d00001 diff --git a/app/routes/__pycache__/dashboard.cpython-314.pyc b/app/routes/__pycache__/dashboard.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a77957a2525ac6a0877d6504f6a4f67d2665f259 GIT binary patch literal 265 zcmdPqaYC z^AdAY_zco{%UM4oKQ~oBF|Q;)GcQ#?CACbyBrz!`HL+ATB~>>mzbHkw zpeSD#CZAYPpkI_TZlX-=wL5jW6GMj$R00TLgW85tSxGDtsU Tdg2xrwQW6DR=y&Zk78 literal 0 HcmV?d00001 diff --git a/app/routes/__pycache__/reports.cpython-314.pyc b/app/routes/__pycache__/reports.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b3963420bde8f919666ed9ede29053a1f2d05626 GIT binary patch literal 261 zcmdPqaYC z^AdAY_zco{%UM4oKQ~oBF|Q;)GcQ#?CACbyBrz!`HL+ATB~>>mzbHkw zpeSD#CZAYPpkI_TZlX-=wL5jW6GMj$R00TLgW85tSxGDtsU Tdg2xrwQW6DR=y;0Z*` literal 0 HcmV?d00001 diff --git a/app/routes/dashboard.py b/app/routes/dashboard.py new file mode 100644 index 0000000..4d4aeca --- /dev/null +++ b/app/routes/dashboard.py @@ -0,0 +1,3 @@ +from flask import Blueprint + +bp = Blueprint("dashboard", __name__) diff --git a/app/routes/entries.py b/app/routes/entries.py new file mode 100644 index 0000000..43e234f --- /dev/null +++ b/app/routes/entries.py @@ -0,0 +1,3 @@ +from flask import Blueprint + +bp = Blueprint("entries", __name__) diff --git a/app/routes/reports.py b/app/routes/reports.py new file mode 100644 index 0000000..3d64de4 --- /dev/null +++ b/app/routes/reports.py @@ -0,0 +1,3 @@ +from flask import Blueprint + +bp = Blueprint("reports", __name__) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..8729b75 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,5 @@ +flask>=3.0 +flask-sqlalchemy>=3.1 +pytest>=8.0 +pytest-flask>=1.3 +gunicorn>=22.0 diff --git a/run.py b/run.py new file mode 100644 index 0000000..488dae9 --- /dev/null +++ b/run.py @@ -0,0 +1,6 @@ +from app import create_app + +app = create_app() + +if __name__ == "__main__": + app.run(debug=True) diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..baaeee7 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,60 @@ +import pytest +from app import create_app, db as _db + + +@pytest.fixture +def app(tmp_path): + config_path = tmp_path / "config.toml" + config_path.write_text(""" +[vehicles.voiture] +name = "Peugeot 308" +fuel = "diesel" +co2_per_km = 142 +cv = 5 + +[vehicles.velo] +name = "Vélo" +fuel = "none" +co2_per_km = 0 + +[journeys.voiture_seule] +name = "Voiture seule" +distances = { voiture = 25 } + +[journeys.voiture_velo] +name = "Voiture + Vélo" +distances = { voiture = 14, velo = 8 } + +[journeys.velo_seul] +name = "Vélo seul" +distances = { velo = 24 } + +[[bareme_kilometrique.2025.cv_5.tranches]] +km_max = 3000 +taux = 0.548 +forfait = 0 + +[[bareme_kilometrique.2025.cv_5.tranches]] +km_max = 6000 +taux = 0.316 +forfait = 699 + +[[bareme_kilometrique.2025.cv_5.tranches]] +km_max = 0 +taux = 0.364 +forfait = 0 +""", encoding="utf-8") + + application = create_app(config_path=str(config_path)) + application.config["TESTING"] = True + application.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///:memory:" + + with application.app_context(): + _db.create_all() + yield application + _db.drop_all() + + +@pytest.fixture +def client(app): + return app.test_client()