PCelia commited on
Commit
180a7cc
·
verified ·
1 Parent(s): 9f0afe1

Upload folder using huggingface_hub

Browse files
.coverage CHANGED
Binary files a/.coverage and b/.coverage differ
 
.github/workflows/ci.yml CHANGED
@@ -21,13 +21,22 @@ jobs:
21
  with:
22
  python-version: "3.12"
23
 
24
- - name: Install uv and sync dependencies
25
  run: |
26
  pip install uv
27
- uv sync --frozen
28
-
29
- - name: Run tests
30
- run: uv run pytest
 
 
 
 
 
 
 
 
 
31
 
32
 
33
  - name: Check Python syntax
 
21
  with:
22
  python-version: "3.12"
23
 
24
+ - name: Run tests with coverage (terminal)
25
  run: |
26
  pip install uv
27
+ uv run pytest --cov=app --cov-report=term-missing
28
+
29
+ - name: Generate HTML coverage report
30
+ run: |
31
+ pip install uv
32
+ uv run pytest --cov=app --cov-report=html
33
+
34
+
35
+ - name: Upload coverage HTML report
36
+ uses: actions/upload-artifact@v4
37
+ with:
38
+ name: coverage-report
39
+ path: htmlcov/
40
 
41
 
42
  - name: Check Python syntax
app/__pycache__/database.cpython-312.pyc CHANGED
Binary files a/app/__pycache__/database.cpython-312.pyc and b/app/__pycache__/database.cpython-312.pyc differ
 
app/__pycache__/feature_engineering.cpython-312.pyc CHANGED
Binary files a/app/__pycache__/feature_engineering.cpython-312.pyc and b/app/__pycache__/feature_engineering.cpython-312.pyc differ
 
app/__pycache__/main.cpython-312.pyc CHANGED
Binary files a/app/__pycache__/main.cpython-312.pyc and b/app/__pycache__/main.cpython-312.pyc differ
 
app/__pycache__/models.cpython-312.pyc CHANGED
Binary files a/app/__pycache__/models.cpython-312.pyc and b/app/__pycache__/models.cpython-312.pyc differ
 
app/database.py CHANGED
@@ -5,19 +5,19 @@ from sqlalchemy.orm import sessionmaker, declarative_base
5
 
6
  load_dotenv()
7
 
8
- # Detect HF Space or test environment
9
  RUNNING_IN_HF = os.getenv("SPACE_ID") is not None
10
  RUNNING_TESTS = os.getenv("ENV") == "test"
11
 
12
- # if RUNNING_IN_HF or RUNNING_TESTS:
13
- # Use SQLite for HuggingFace and for tests
14
  if True:
15
 
16
  DATABASE_URL = "sqlite:///./futurisys.db"
17
 
18
 
19
  else:
20
- # Normal PostgreSQL configuration
21
  DB_USER = os.getenv("DB_USER")
22
  DB_PASSWORD = os.getenv("DB_PASSWORD")
23
  DB_HOST = os.getenv("DB_HOST")
 
5
 
6
  load_dotenv()
7
 
8
+ # Détecter environnement HF Space ou de tests
9
  RUNNING_IN_HF = os.getenv("SPACE_ID") is not None
10
  RUNNING_TESTS = os.getenv("ENV") == "test"
11
 
12
+ # Utiliser SQLite pour Hugging Face et pour les tests
13
+ # Sinon : configuration PostgreSQL normale**
14
  if True:
15
 
16
  DATABASE_URL = "sqlite:///./futurisys.db"
17
 
18
 
19
  else:
20
+ # PostgreSQL configuration normale
21
  DB_USER = os.getenv("DB_USER")
22
  DB_PASSWORD = os.getenv("DB_PASSWORD")
23
  DB_HOST = os.getenv("DB_HOST")
app/main.py CHANGED
@@ -1,5 +1,3 @@
1
- # app/main.py
2
-
3
  from fastapi import FastAPI
4
  from pydantic import BaseModel
5
  from typing import Literal
@@ -10,7 +8,6 @@ from app.models import Input, Output, Employe
10
  import datetime
11
  from app.feature_engineering import transform_fe
12
  from fastapi import Query
13
-
14
  from app.database import DATABASE_URL
15
 
16
 
@@ -65,7 +62,6 @@ class PredictionRawData(BaseModel):
65
  app = FastAPI(title="API Futurisys")
66
 
67
 
68
-
69
  @app.get("/")
70
  def read_root():
71
  return {
@@ -85,7 +81,6 @@ def read_threshold():
85
 
86
  @app.post("/predict")
87
  def predict(data: PredictionRawData):
88
- #test
89
  # Convertir en DataFrame
90
  df = pd.DataFrame([data.dict()])
91
  df = transform_fe(df)
 
 
 
1
  from fastapi import FastAPI
2
  from pydantic import BaseModel
3
  from typing import Literal
 
8
  import datetime
9
  from app.feature_engineering import transform_fe
10
  from fastapi import Query
 
11
  from app.database import DATABASE_URL
12
 
13
 
 
62
  app = FastAPI(title="API Futurisys")
63
 
64
 
 
65
  @app.get("/")
66
  def read_root():
67
  return {
 
81
 
82
  @app.post("/predict")
83
  def predict(data: PredictionRawData):
 
84
  # Convertir en DataFrame
85
  df = pd.DataFrame([data.dict()])
86
  df = transform_fe(df)
app/models.py CHANGED
@@ -26,9 +26,6 @@ class Employe(Base):
26
  __tablename__ = "employes"
27
 
28
  employee_id = Column(Integer, primary_key=True)
29
-
30
-
31
-
32
  age = Column(Integer)
33
  revenu_mensuel = Column(Float)
34
  statut_marital = Column(String)
 
26
  __tablename__ = "employes"
27
 
28
  employee_id = Column(Integer, primary_key=True)
 
 
 
29
  age = Column(Integer)
30
  revenu_mensuel = Column(Float)
31
  statut_marital = Column(String)
employes.csv ADDED
The diff for this file is too large to render. See raw diff
 
futurisys.db CHANGED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:168856bb68c600db9a2efbea6ac1e370b0329831964057fcaa63415c51a0fb25
3
  size 159744
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:11af468604e39ae740c9f75c37bf35ad9696e3c6dd5645bf8123823de5771320
3
  size 159744
import_csv_to_sqlite.py ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import sqlite3
2
+ import csv
3
+
4
+ db = sqlite3.connect("futurisys.db")
5
+ cursor = db.cursor()
6
+
7
+ # Supprimer l'ancienne table si elle existe
8
+ cursor.execute("DROP TABLE IF EXISTS employes;")
9
+
10
+ # Créer la table avec EXACTEMENT les colonnes du CSV
11
+ cursor.execute("""
12
+ CREATE TABLE employes (
13
+ employee_id INTEGER,
14
+ age INTEGER,
15
+ revenu_mensuel FLOAT,
16
+ statut_marital TEXT,
17
+ departement TEXT,
18
+ poste TEXT,
19
+ annee_experience_totale INTEGER,
20
+ annees_dans_l_entreprise INTEGER,
21
+ annees_dans_le_poste_actuel INTEGER,
22
+ satisfaction_employee_environnement INTEGER,
23
+ note_evaluation_precedente FLOAT,
24
+ satisfaction_employee_nature_travail INTEGER,
25
+ satisfaction_employee_equipe INTEGER,
26
+ satisfaction_employee_equilibre_pro_perso INTEGER,
27
+ note_evaluation_actuelle FLOAT,
28
+ heure_supplementaires TEXT,
29
+ augementation_salaire_precedente FLOAT,
30
+ nombre_participation_pee INTEGER,
31
+ frequence_deplacement TEXT,
32
+ annes_sous_responsable_actuel INTEGER
33
+ );
34
+ """)
35
+
36
+ # Charger le CSV
37
+ with open("employes.csv", newline='', encoding="utf-8") as f:
38
+ reader = csv.DictReader(f)
39
+ rows = [(
40
+ row["employee_id"],
41
+ row["age"],
42
+ row["revenu_mensuel"],
43
+ row["statut_marital"],
44
+ row["departement"],
45
+ row["poste"],
46
+ row["annee_experience_totale"],
47
+ row["annees_dans_l_entreprise"],
48
+ row["annees_dans_le_poste_actuel"],
49
+ row["satisfaction_employee_environnement"],
50
+ row["note_evaluation_precedente"],
51
+ row["satisfaction_employee_nature_travail"],
52
+ row["satisfaction_employee_equipe"],
53
+ row["satisfaction_employee_equilibre_pro_perso"],
54
+ row["note_evaluation_actuelle"],
55
+ row["heure_supplementaires"],
56
+ row["augementation_salaire_precedente"],
57
+ row["nombre_participation_pee"],
58
+ row["frequence_deplacement"],
59
+ row["annes_sous_responsable_actuel"]
60
+ ) for row in reader]
61
+
62
+ # Insérer les données
63
+ cursor.executemany("""
64
+ INSERT INTO employes VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
65
+ """, rows)
66
+
67
+ db.commit()
68
+ db.close()
69
+
70
+ print("🎉 Import terminé à 100 % avec 20 colonnes !")
pyproject.toml CHANGED
@@ -20,7 +20,7 @@ dependencies = [
20
  "pytest-cov",
21
  "httpx",
22
  "sqlalchemy",
23
- "python-dotenv"
24
  ]
25
 
26
 
 
20
  "pytest-cov",
21
  "httpx",
22
  "sqlalchemy",
23
+ "python-dotenv",
24
  ]
25
 
26
 
requirements.txt CHANGED
@@ -7,3 +7,4 @@ seaborn
7
  scikit-learn
8
  imbalanced-learn
9
  shap
 
 
7
  scikit-learn
8
  imbalanced-learn
9
  shap
10
+ httpx
tests/__pycache__/test_api.cpython-312-pytest-9.0.1.pyc ADDED
Binary file (17.1 kB). View file
 
tests/__pycache__/test_basic.cpython-312-pytest-9.0.1.pyc ADDED
Binary file (869 Bytes). View file
 
tests/__pycache__/test_main_import.cpython-312-pytest-9.0.1.pyc ADDED
Binary file (651 Bytes). View file
 
tests/__pycache__/test_schema_prediction_raw_data.cpython-312-pytest-9.0.1.pyc ADDED
Binary file (3.82 kB). View file
 
tests/__pycache__/test_transform_fe.cpython-312-pytest-9.0.1.pyc ADDED
Binary file (5.21 kB). View file
 
tests/test_api.py CHANGED
@@ -1,5 +1,7 @@
1
  from fastapi.testclient import TestClient
2
  from app.main import app
 
 
3
 
4
  client = TestClient(app)
5
 
@@ -104,3 +106,61 @@ def test_predict_missing_field():
104
 
105
  response = client.post("/predict", json=payload)
106
  assert response.status_code == 422
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  from fastapi.testclient import TestClient
2
  from app.main import app
3
+ from app.main import get_db
4
+
5
 
6
  client = TestClient(app)
7
 
 
106
 
107
  response = client.post("/predict", json=payload)
108
  assert response.status_code == 422
109
+
110
+ def test_predict_from_db_employe_not_found():
111
+ response = client.post("/predict_from_db_employe?employee_id=999999")
112
+ assert response.status_code == 200
113
+ assert "Aucun employé trouvé" in response.json()["message"]
114
+
115
+ from app.database import SessionLocal
116
+ from app.models import Employe
117
+
118
+ def test_predict_from_db_employe_found():
119
+ # 1. Créer un employé dans la base
120
+ db = SessionLocal()
121
+ employe = Employe(
122
+ employee_id=999,
123
+ age=30,
124
+ revenu_mensuel=2500.0,
125
+ statut_marital="Marié(e)",
126
+ departement="IT",
127
+ poste="Développeur",
128
+ annee_experience_totale=5,
129
+ annees_dans_l_entreprise=2,
130
+ annees_dans_le_poste_actuel=2,
131
+ satisfaction_employee_environnement=3,
132
+ note_evaluation_precedente=4.2,
133
+ satisfaction_employee_nature_travail=4,
134
+ satisfaction_employee_equipe=4,
135
+ satisfaction_employee_equilibre_pro_perso=3,
136
+ note_evaluation_actuelle=4.5,
137
+ heure_supplementaires="Oui",
138
+ augementation_salaire_precedente=2.0,
139
+ nombre_participation_pee=1,
140
+ frequence_deplacement="Rare",
141
+ annes_sous_responsable_actuel=1
142
+ )
143
+ db.add(employe)
144
+ db.commit()
145
+
146
+ # 2. Appeler l'endpoint
147
+ response = client.post("/predict_from_db_employe?employee_id=999")
148
+
149
+ # 3. Assertions
150
+ assert response.status_code == 200
151
+ res = response.json()
152
+ assert "probabilité" in res
153
+ assert "prédiction" in res
154
+ assert isinstance(res["probabilité"], float)
155
+ assert isinstance(res["prédiction"], bool)
156
+
157
+
158
+ def test_get_db():
159
+ gen = get_db() # on récupère le générateur
160
+ db = next(gen) # exécute "db = SessionLocal()" et "yield db"
161
+ assert db is not None # couvre la partie try / yield
162
+ try:
163
+ next(gen) # va provoquer StopIteration
164
+ except StopIteration:
165
+ pass # couvre le finally: db.close()
166
+
tests/test_main_import.py ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ def test_main_runs():
2
+ import app.main
3
+ assert True
tests/test_schema_prediction_raw_data.py CHANGED
@@ -1,5 +1,6 @@
1
  from pydantic import ValidationError
2
  from app.main import PredictionRawData
 
3
 
4
  def test_schema_accepts_valid_age():
5
  data = {
@@ -35,6 +36,18 @@ def test_schema_rejects_invalid_age():
35
 
36
  try:
37
  PredictionRawData(**data)
38
- assert False # si ça ne plante pas, c'est mauvais
39
  except ValidationError:
40
- assert True # si ça plante comme prévu, c'est bon
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  from pydantic import ValidationError
2
  from app.main import PredictionRawData
3
+ from app.main import get_db
4
 
5
  def test_schema_accepts_valid_age():
6
  data = {
 
36
 
37
  try:
38
  PredictionRawData(**data)
39
+ assert False # si ça ne plante pas, erreur
40
  except ValidationError:
41
+ assert True # si ça plante comme prévu, ok
42
+
43
+
44
+
45
+ def test_get_db():
46
+ gen = get_db() # on récupère le générateur
47
+ db = next(gen) # exécute "db = SessionLocal()" et "yield db"
48
+ assert db is not None # couvre la partie try / yield
49
+ try:
50
+ next(gen) # va provoquer StopIteration
51
+ except StopIteration:
52
+ pass # couvre le finally: db.close()
53
+
uv.lock CHANGED
@@ -37,6 +37,15 @@ wheels = [
37
  { url = "https://files.pythonhosted.org/packages/7f/9c/36c5c37947ebfb8c7f22e0eb6e4d188ee2d53aa3880f3f2744fb894f0cb1/anyio-4.12.0-py3-none-any.whl", hash = "sha256:dad2376a628f98eeca4881fc56cd06affd18f659b17a747d3ff0307ced94b1bb", size = 113362, upload-time = "2025-11-28T23:36:57.897Z" },
38
  ]
39
 
 
 
 
 
 
 
 
 
 
40
  [[package]]
41
  name = "click"
42
  version = "8.3.1"
@@ -272,6 +281,45 @@ wheels = [
272
  { url = "https://files.pythonhosted.org/packages/0c/14/634f7daea5ffe6a5f7a0322ba8e1a0e23c9257b80aa91458107896d1dfc7/fonttools-4.61.0-py3-none-any.whl", hash = "sha256:276f14c560e6f98d24ef7f5f44438e55ff5a67f78fa85236b218462c9f5d0635", size = 1144485, upload-time = "2025-11-28T17:05:47.573Z" },
273
  ]
274
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
275
  [[package]]
276
  name = "h11"
277
  version = "0.16.0"
@@ -281,6 +329,34 @@ wheels = [
281
  { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" },
282
  ]
283
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
284
  [[package]]
285
  name = "idna"
286
  version = "3.11"
@@ -474,6 +550,7 @@ version = "0.1.0"
474
  source = { virtual = "." }
475
  dependencies = [
476
  { name = "fastapi" },
 
477
  { name = "imbalanced-learn" },
478
  { name = "joblib" },
479
  { name = "matplotlib" },
@@ -482,16 +559,19 @@ dependencies = [
482
  { name = "pydantic" },
483
  { name = "pytest" },
484
  { name = "pytest-cov" },
 
485
  { name = "scikit-learn" },
486
  { name = "seaborn" },
487
  { name = "shap", version = "0.49.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.14'" },
488
  { name = "shap", version = "0.50.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.14'" },
 
489
  { name = "uvicorn" },
490
  ]
491
 
492
  [package.metadata]
493
  requires-dist = [
494
  { name = "fastapi" },
 
495
  { name = "imbalanced-learn" },
496
  { name = "joblib" },
497
  { name = "matplotlib" },
@@ -500,9 +580,11 @@ requires-dist = [
500
  { name = "pydantic" },
501
  { name = "pytest" },
502
  { name = "pytest-cov" },
 
503
  { name = "scikit-learn" },
504
  { name = "seaborn" },
505
  { name = "shap" },
 
506
  { name = "uvicorn" },
507
  ]
508
 
@@ -871,6 +953,15 @@ wheels = [
871
  { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" },
872
  ]
873
 
 
 
 
 
 
 
 
 
 
874
  [[package]]
875
  name = "pytz"
876
  version = "2025.2"
@@ -1089,6 +1180,35 @@ wheels = [
1089
  { url = "https://files.pythonhosted.org/packages/63/81/9ef641ff4e12cbcca30e54e72fb0951a2ba195d0cda0ba4100e532d929db/slicer-0.0.8-py3-none-any.whl", hash = "sha256:6c206258543aecd010d497dc2eca9d2805860a0b3758673903456b7df7934dc3", size = 15251, upload-time = "2024-03-09T07:03:07.708Z" },
1090
  ]
1091
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1092
  [[package]]
1093
  name = "starlette"
1094
  version = "0.50.0"
 
37
  { url = "https://files.pythonhosted.org/packages/7f/9c/36c5c37947ebfb8c7f22e0eb6e4d188ee2d53aa3880f3f2744fb894f0cb1/anyio-4.12.0-py3-none-any.whl", hash = "sha256:dad2376a628f98eeca4881fc56cd06affd18f659b17a747d3ff0307ced94b1bb", size = 113362, upload-time = "2025-11-28T23:36:57.897Z" },
38
  ]
39
 
40
+ [[package]]
41
+ name = "certifi"
42
+ version = "2025.11.12"
43
+ source = { registry = "https://pypi.org/simple" }
44
+ sdist = { url = "https://files.pythonhosted.org/packages/a2/8c/58f469717fa48465e4a50c014a0400602d3c437d7c0c468e17ada824da3a/certifi-2025.11.12.tar.gz", hash = "sha256:d8ab5478f2ecd78af242878415affce761ca6bc54a22a27e026d7c25357c3316", size = 160538, upload-time = "2025-11-12T02:54:51.517Z" }
45
+ wheels = [
46
+ { url = "https://files.pythonhosted.org/packages/70/7d/9bc192684cea499815ff478dfcdc13835ddf401365057044fb721ec6bddb/certifi-2025.11.12-py3-none-any.whl", hash = "sha256:97de8790030bbd5c2d96b7ec782fc2f7820ef8dba6db909ccf95449f2d062d4b", size = 159438, upload-time = "2025-11-12T02:54:49.735Z" },
47
+ ]
48
+
49
  [[package]]
50
  name = "click"
51
  version = "8.3.1"
 
281
  { url = "https://files.pythonhosted.org/packages/0c/14/634f7daea5ffe6a5f7a0322ba8e1a0e23c9257b80aa91458107896d1dfc7/fonttools-4.61.0-py3-none-any.whl", hash = "sha256:276f14c560e6f98d24ef7f5f44438e55ff5a67f78fa85236b218462c9f5d0635", size = 1144485, upload-time = "2025-11-28T17:05:47.573Z" },
282
  ]
283
 
284
+ [[package]]
285
+ name = "greenlet"
286
+ version = "3.3.0"
287
+ source = { registry = "https://pypi.org/simple" }
288
+ sdist = { url = "https://files.pythonhosted.org/packages/c7/e5/40dbda2736893e3e53d25838e0f19a2b417dfc122b9989c91918db30b5d3/greenlet-3.3.0.tar.gz", hash = "sha256:a82bb225a4e9e4d653dd2fb7b8b2d36e4fb25bc0165422a11e48b88e9e6f78fb", size = 190651, upload-time = "2025-12-04T14:49:44.05Z" }
289
+ wheels = [
290
+ { url = "https://files.pythonhosted.org/packages/f8/0a/a3871375c7b9727edaeeea994bfff7c63ff7804c9829c19309ba2e058807/greenlet-3.3.0-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:b01548f6e0b9e9784a2c99c5651e5dc89ffcbe870bc5fb2e5ef864e9cc6b5dcb", size = 276379, upload-time = "2025-12-04T14:23:30.498Z" },
291
+ { url = "https://files.pythonhosted.org/packages/43/ab/7ebfe34dce8b87be0d11dae91acbf76f7b8246bf9d6b319c741f99fa59c6/greenlet-3.3.0-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:349345b770dc88f81506c6861d22a6ccd422207829d2c854ae2af8025af303e3", size = 597294, upload-time = "2025-12-04T14:50:06.847Z" },
292
+ { url = "https://files.pythonhosted.org/packages/a4/39/f1c8da50024feecd0793dbd5e08f526809b8ab5609224a2da40aad3a7641/greenlet-3.3.0-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e8e18ed6995e9e2c0b4ed264d2cf89260ab3ac7e13555b8032b25a74c6d18655", size = 607742, upload-time = "2025-12-04T14:57:42.349Z" },
293
+ { url = "https://files.pythonhosted.org/packages/77/cb/43692bcd5f7a0da6ec0ec6d58ee7cddb606d055ce94a62ac9b1aa481e969/greenlet-3.3.0-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c024b1e5696626890038e34f76140ed1daf858e37496d33f2af57f06189e70d7", size = 622297, upload-time = "2025-12-04T15:07:13.552Z" },
294
+ { url = "https://files.pythonhosted.org/packages/75/b0/6bde0b1011a60782108c01de5913c588cf51a839174538d266de15e4bf4d/greenlet-3.3.0-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:047ab3df20ede6a57c35c14bf5200fcf04039d50f908270d3f9a7a82064f543b", size = 609885, upload-time = "2025-12-04T14:26:02.368Z" },
295
+ { url = "https://files.pythonhosted.org/packages/49/0e/49b46ac39f931f59f987b7cd9f34bfec8ef81d2a1e6e00682f55be5de9f4/greenlet-3.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2d9ad37fc657b1102ec880e637cccf20191581f75c64087a549e66c57e1ceb53", size = 1567424, upload-time = "2025-12-04T15:04:23.757Z" },
296
+ { url = "https://files.pythonhosted.org/packages/05/f5/49a9ac2dff7f10091935def9165c90236d8f175afb27cbed38fb1d61ab6b/greenlet-3.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:83cd0e36932e0e7f36a64b732a6f60c2fc2df28c351bae79fbaf4f8092fe7614", size = 1636017, upload-time = "2025-12-04T14:27:29.688Z" },
297
+ { url = "https://files.pythonhosted.org/packages/6c/79/3912a94cf27ec503e51ba493692d6db1e3cd8ac7ac52b0b47c8e33d7f4f9/greenlet-3.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:a7a34b13d43a6b78abf828a6d0e87d3385680eaf830cd60d20d52f249faabf39", size = 301964, upload-time = "2025-12-04T14:36:58.316Z" },
298
+ { url = "https://files.pythonhosted.org/packages/02/2f/28592176381b9ab2cafa12829ba7b472d177f3acc35d8fbcf3673d966fff/greenlet-3.3.0-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:a1e41a81c7e2825822f4e068c48cb2196002362619e2d70b148f20a831c00739", size = 275140, upload-time = "2025-12-04T14:23:01.282Z" },
299
+ { url = "https://files.pythonhosted.org/packages/2c/80/fbe937bf81e9fca98c981fe499e59a3f45df2a04da0baa5c2be0dca0d329/greenlet-3.3.0-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9f515a47d02da4d30caaa85b69474cec77b7929b2e936ff7fb853d42f4bf8808", size = 599219, upload-time = "2025-12-04T14:50:08.309Z" },
300
+ { url = "https://files.pythonhosted.org/packages/c2/ff/7c985128f0514271b8268476af89aee6866df5eec04ac17dcfbc676213df/greenlet-3.3.0-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7d2d9fd66bfadf230b385fdc90426fcd6eb64db54b40c495b72ac0feb5766c54", size = 610211, upload-time = "2025-12-04T14:57:43.968Z" },
301
+ { url = "https://files.pythonhosted.org/packages/79/07/c47a82d881319ec18a4510bb30463ed6891f2ad2c1901ed5ec23d3de351f/greenlet-3.3.0-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:30a6e28487a790417d036088b3bcb3f3ac7d8babaa7d0139edbaddebf3af9492", size = 624311, upload-time = "2025-12-04T15:07:14.697Z" },
302
+ { url = "https://files.pythonhosted.org/packages/fd/8e/424b8c6e78bd9837d14ff7df01a9829fc883ba2ab4ea787d4f848435f23f/greenlet-3.3.0-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:087ea5e004437321508a8d6f20efc4cfec5e3c30118e1417ea96ed1d93950527", size = 612833, upload-time = "2025-12-04T14:26:03.669Z" },
303
+ { url = "https://files.pythonhosted.org/packages/b5/ba/56699ff9b7c76ca12f1cdc27a886d0f81f2189c3455ff9f65246780f713d/greenlet-3.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ab97cf74045343f6c60a39913fa59710e4bd26a536ce7ab2397adf8b27e67c39", size = 1567256, upload-time = "2025-12-04T15:04:25.276Z" },
304
+ { url = "https://files.pythonhosted.org/packages/1e/37/f31136132967982d698c71a281a8901daf1a8fbab935dce7c0cf15f942cc/greenlet-3.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5375d2e23184629112ca1ea89a53389dddbffcf417dad40125713d88eb5f96e8", size = 1636483, upload-time = "2025-12-04T14:27:30.804Z" },
305
+ { url = "https://files.pythonhosted.org/packages/7e/71/ba21c3fb8c5dce83b8c01f458a42e99ffdb1963aeec08fff5a18588d8fd7/greenlet-3.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:9ee1942ea19550094033c35d25d20726e4f1c40d59545815e1128ac58d416d38", size = 301833, upload-time = "2025-12-04T14:32:23.929Z" },
306
+ { url = "https://files.pythonhosted.org/packages/d7/7c/f0a6d0ede2c7bf092d00bc83ad5bafb7e6ec9b4aab2fbdfa6f134dc73327/greenlet-3.3.0-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:60c2ef0f578afb3c8d92ea07ad327f9a062547137afe91f38408f08aacab667f", size = 275671, upload-time = "2025-12-04T14:23:05.267Z" },
307
+ { url = "https://files.pythonhosted.org/packages/44/06/dac639ae1a50f5969d82d2e3dd9767d30d6dbdbab0e1a54010c8fe90263c/greenlet-3.3.0-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0a5d554d0712ba1de0a6c94c640f7aeba3f85b3a6e1f2899c11c2c0428da9365", size = 646360, upload-time = "2025-12-04T14:50:10.026Z" },
308
+ { url = "https://files.pythonhosted.org/packages/e0/94/0fb76fe6c5369fba9bf98529ada6f4c3a1adf19e406a47332245ef0eb357/greenlet-3.3.0-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3a898b1e9c5f7307ebbde4102908e6cbfcb9ea16284a3abe15cab996bee8b9b3", size = 658160, upload-time = "2025-12-04T14:57:45.41Z" },
309
+ { url = "https://files.pythonhosted.org/packages/93/79/d2c70cae6e823fac36c3bbc9077962105052b7ef81db2f01ec3b9bf17e2b/greenlet-3.3.0-cp314-cp314-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:dcd2bdbd444ff340e8d6bdf54d2f206ccddbb3ccfdcd3c25bf4afaa7b8f0cf45", size = 671388, upload-time = "2025-12-04T15:07:15.789Z" },
310
+ { url = "https://files.pythonhosted.org/packages/b8/14/bab308fc2c1b5228c3224ec2bf928ce2e4d21d8046c161e44a2012b5203e/greenlet-3.3.0-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5773edda4dc00e173820722711d043799d3adb4f01731f40619e07ea2750b955", size = 660166, upload-time = "2025-12-04T14:26:05.099Z" },
311
+ { url = "https://files.pythonhosted.org/packages/4b/d2/91465d39164eaa0085177f61983d80ffe746c5a1860f009811d498e7259c/greenlet-3.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ac0549373982b36d5fd5d30beb8a7a33ee541ff98d2b502714a09f1169f31b55", size = 1615193, upload-time = "2025-12-04T15:04:27.041Z" },
312
+ { url = "https://files.pythonhosted.org/packages/42/1b/83d110a37044b92423084d52d5d5a3b3a73cafb51b547e6d7366ff62eff1/greenlet-3.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d198d2d977460358c3b3a4dc844f875d1adb33817f0613f663a656f463764ccc", size = 1683653, upload-time = "2025-12-04T14:27:32.366Z" },
313
+ { url = "https://files.pythonhosted.org/packages/7c/9a/9030e6f9aa8fd7808e9c31ba4c38f87c4f8ec324ee67431d181fe396d705/greenlet-3.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:73f51dd0e0bdb596fb0417e475fa3c5e32d4c83638296e560086b8d7da7c4170", size = 305387, upload-time = "2025-12-04T14:26:51.063Z" },
314
+ { url = "https://files.pythonhosted.org/packages/a0/66/bd6317bc5932accf351fc19f177ffba53712a202f9df10587da8df257c7e/greenlet-3.3.0-cp314-cp314t-macosx_11_0_universal2.whl", hash = "sha256:d6ed6f85fae6cdfdb9ce04c9bf7a08d666cfcfb914e7d006f44f840b46741931", size = 282638, upload-time = "2025-12-04T14:25:20.941Z" },
315
+ { url = "https://files.pythonhosted.org/packages/30/cf/cc81cb030b40e738d6e69502ccbd0dd1bced0588e958f9e757945de24404/greenlet-3.3.0-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d9125050fcf24554e69c4cacb086b87b3b55dc395a8b3ebe6487b045b2614388", size = 651145, upload-time = "2025-12-04T14:50:11.039Z" },
316
+ { url = "https://files.pythonhosted.org/packages/9c/ea/1020037b5ecfe95ca7df8d8549959baceb8186031da83d5ecceff8b08cd2/greenlet-3.3.0-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:87e63ccfa13c0a0f6234ed0add552af24cc67dd886731f2261e46e241608bee3", size = 654236, upload-time = "2025-12-04T14:57:47.007Z" },
317
+ { url = "https://files.pythonhosted.org/packages/69/cc/1e4bae2e45ca2fa55299f4e85854606a78ecc37fead20d69322f96000504/greenlet-3.3.0-cp314-cp314t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2662433acbca297c9153a4023fe2161c8dcfdcc91f10433171cf7e7d94ba2221", size = 662506, upload-time = "2025-12-04T15:07:16.906Z" },
318
+ { url = "https://files.pythonhosted.org/packages/57/b9/f8025d71a6085c441a7eaff0fd928bbb275a6633773667023d19179fe815/greenlet-3.3.0-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3c6e9b9c1527a78520357de498b0e709fb9e2f49c3a513afd5a249007261911b", size = 653783, upload-time = "2025-12-04T14:26:06.225Z" },
319
+ { url = "https://files.pythonhosted.org/packages/f6/c7/876a8c7a7485d5d6b5c6821201d542ef28be645aa024cfe1145b35c120c1/greenlet-3.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:286d093f95ec98fdd92fcb955003b8a3d054b4e2cab3e2707a5039e7b50520fd", size = 1614857, upload-time = "2025-12-04T15:04:28.484Z" },
320
+ { url = "https://files.pythonhosted.org/packages/4f/dc/041be1dff9f23dac5f48a43323cd0789cb798342011c19a248d9c9335536/greenlet-3.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c10513330af5b8ae16f023e8ddbfb486ab355d04467c4679c5cfe4659975dd9", size = 1676034, upload-time = "2025-12-04T14:27:33.531Z" },
321
+ ]
322
+
323
  [[package]]
324
  name = "h11"
325
  version = "0.16.0"
 
329
  { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" },
330
  ]
331
 
332
+ [[package]]
333
+ name = "httpcore"
334
+ version = "1.0.9"
335
+ source = { registry = "https://pypi.org/simple" }
336
+ dependencies = [
337
+ { name = "certifi" },
338
+ { name = "h11" },
339
+ ]
340
+ sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" }
341
+ wheels = [
342
+ { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" },
343
+ ]
344
+
345
+ [[package]]
346
+ name = "httpx"
347
+ version = "0.28.1"
348
+ source = { registry = "https://pypi.org/simple" }
349
+ dependencies = [
350
+ { name = "anyio" },
351
+ { name = "certifi" },
352
+ { name = "httpcore" },
353
+ { name = "idna" },
354
+ ]
355
+ sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" }
356
+ wheels = [
357
+ { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" },
358
+ ]
359
+
360
  [[package]]
361
  name = "idna"
362
  version = "3.11"
 
550
  source = { virtual = "." }
551
  dependencies = [
552
  { name = "fastapi" },
553
+ { name = "httpx" },
554
  { name = "imbalanced-learn" },
555
  { name = "joblib" },
556
  { name = "matplotlib" },
 
559
  { name = "pydantic" },
560
  { name = "pytest" },
561
  { name = "pytest-cov" },
562
+ { name = "python-dotenv" },
563
  { name = "scikit-learn" },
564
  { name = "seaborn" },
565
  { name = "shap", version = "0.49.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.14'" },
566
  { name = "shap", version = "0.50.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.14'" },
567
+ { name = "sqlalchemy" },
568
  { name = "uvicorn" },
569
  ]
570
 
571
  [package.metadata]
572
  requires-dist = [
573
  { name = "fastapi" },
574
+ { name = "httpx" },
575
  { name = "imbalanced-learn" },
576
  { name = "joblib" },
577
  { name = "matplotlib" },
 
580
  { name = "pydantic" },
581
  { name = "pytest" },
582
  { name = "pytest-cov" },
583
+ { name = "python-dotenv" },
584
  { name = "scikit-learn" },
585
  { name = "seaborn" },
586
  { name = "shap" },
587
+ { name = "sqlalchemy" },
588
  { name = "uvicorn" },
589
  ]
590
 
 
953
  { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" },
954
  ]
955
 
956
+ [[package]]
957
+ name = "python-dotenv"
958
+ version = "1.2.1"
959
+ source = { registry = "https://pypi.org/simple" }
960
+ sdist = { url = "https://files.pythonhosted.org/packages/f0/26/19cadc79a718c5edbec86fd4919a6b6d3f681039a2f6d66d14be94e75fb9/python_dotenv-1.2.1.tar.gz", hash = "sha256:42667e897e16ab0d66954af0e60a9caa94f0fd4ecf3aaf6d2d260eec1aa36ad6", size = 44221, upload-time = "2025-10-26T15:12:10.434Z" }
961
+ wheels = [
962
+ { url = "https://files.pythonhosted.org/packages/14/1b/a298b06749107c305e1fe0f814c6c74aea7b2f1e10989cb30f544a1b3253/python_dotenv-1.2.1-py3-none-any.whl", hash = "sha256:b81ee9561e9ca4004139c6cbba3a238c32b03e4894671e181b671e8cb8425d61", size = 21230, upload-time = "2025-10-26T15:12:09.109Z" },
963
+ ]
964
+
965
  [[package]]
966
  name = "pytz"
967
  version = "2025.2"
 
1180
  { url = "https://files.pythonhosted.org/packages/63/81/9ef641ff4e12cbcca30e54e72fb0951a2ba195d0cda0ba4100e532d929db/slicer-0.0.8-py3-none-any.whl", hash = "sha256:6c206258543aecd010d497dc2eca9d2805860a0b3758673903456b7df7934dc3", size = 15251, upload-time = "2024-03-09T07:03:07.708Z" },
1181
  ]
1182
 
1183
+ [[package]]
1184
+ name = "sqlalchemy"
1185
+ version = "2.0.44"
1186
+ source = { registry = "https://pypi.org/simple" }
1187
+ dependencies = [
1188
+ { name = "greenlet", marker = "platform_machine == 'AMD64' or platform_machine == 'WIN32' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'ppc64le' or platform_machine == 'win32' or platform_machine == 'x86_64'" },
1189
+ { name = "typing-extensions" },
1190
+ ]
1191
+ sdist = { url = "https://files.pythonhosted.org/packages/f0/f2/840d7b9496825333f532d2e3976b8eadbf52034178aac53630d09fe6e1ef/sqlalchemy-2.0.44.tar.gz", hash = "sha256:0ae7454e1ab1d780aee69fd2aae7d6b8670a581d8847f2d1e0f7ddfbf47e5a22", size = 9819830, upload-time = "2025-10-10T14:39:12.935Z" }
1192
+ wheels = [
1193
+ { url = "https://files.pythonhosted.org/packages/62/c4/59c7c9b068e6813c898b771204aad36683c96318ed12d4233e1b18762164/sqlalchemy-2.0.44-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:72fea91746b5890f9e5e0997f16cbf3d53550580d76355ba2d998311b17b2250", size = 2139675, upload-time = "2025-10-10T16:03:31.064Z" },
1194
+ { url = "https://files.pythonhosted.org/packages/d6/ae/eeb0920537a6f9c5a3708e4a5fc55af25900216bdb4847ec29cfddf3bf3a/sqlalchemy-2.0.44-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:585c0c852a891450edbb1eaca8648408a3cc125f18cf433941fa6babcc359e29", size = 2127726, upload-time = "2025-10-10T16:03:35.934Z" },
1195
+ { url = "https://files.pythonhosted.org/packages/d8/d5/2ebbabe0379418eda8041c06b0b551f213576bfe4c2f09d77c06c07c8cc5/sqlalchemy-2.0.44-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9b94843a102efa9ac68a7a30cd46df3ff1ed9c658100d30a725d10d9c60a2f44", size = 3327603, upload-time = "2025-10-10T15:35:28.322Z" },
1196
+ { url = "https://files.pythonhosted.org/packages/45/e5/5aa65852dadc24b7d8ae75b7efb8d19303ed6ac93482e60c44a585930ea5/sqlalchemy-2.0.44-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:119dc41e7a7defcefc57189cfa0e61b1bf9c228211aba432b53fb71ef367fda1", size = 3337842, upload-time = "2025-10-10T15:43:45.431Z" },
1197
+ { url = "https://files.pythonhosted.org/packages/41/92/648f1afd3f20b71e880ca797a960f638d39d243e233a7082c93093c22378/sqlalchemy-2.0.44-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0765e318ee9179b3718c4fd7ba35c434f4dd20332fbc6857a5e8df17719c24d7", size = 3264558, upload-time = "2025-10-10T15:35:29.93Z" },
1198
+ { url = "https://files.pythonhosted.org/packages/40/cf/e27d7ee61a10f74b17740918e23cbc5bc62011b48282170dc4c66da8ec0f/sqlalchemy-2.0.44-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2e7b5b079055e02d06a4308d0481658e4f06bc7ef211567edc8f7d5dce52018d", size = 3301570, upload-time = "2025-10-10T15:43:48.407Z" },
1199
+ { url = "https://files.pythonhosted.org/packages/3b/3d/3116a9a7b63e780fb402799b6da227435be878b6846b192f076d2f838654/sqlalchemy-2.0.44-cp312-cp312-win32.whl", hash = "sha256:846541e58b9a81cce7dee8329f352c318de25aa2f2bbe1e31587eb1f057448b4", size = 2103447, upload-time = "2025-10-10T15:03:21.678Z" },
1200
+ { url = "https://files.pythonhosted.org/packages/25/83/24690e9dfc241e6ab062df82cc0df7f4231c79ba98b273fa496fb3dd78ed/sqlalchemy-2.0.44-cp312-cp312-win_amd64.whl", hash = "sha256:7cbcb47fd66ab294703e1644f78971f6f2f1126424d2b300678f419aa73c7b6e", size = 2130912, upload-time = "2025-10-10T15:03:24.656Z" },
1201
+ { url = "https://files.pythonhosted.org/packages/45/d3/c67077a2249fdb455246e6853166360054c331db4613cda3e31ab1cadbef/sqlalchemy-2.0.44-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ff486e183d151e51b1d694c7aa1695747599bb00b9f5f604092b54b74c64a8e1", size = 2135479, upload-time = "2025-10-10T16:03:37.671Z" },
1202
+ { url = "https://files.pythonhosted.org/packages/2b/91/eabd0688330d6fd114f5f12c4f89b0d02929f525e6bf7ff80aa17ca802af/sqlalchemy-2.0.44-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0b1af8392eb27b372ddb783b317dea0f650241cea5bd29199b22235299ca2e45", size = 2123212, upload-time = "2025-10-10T16:03:41.755Z" },
1203
+ { url = "https://files.pythonhosted.org/packages/b0/bb/43e246cfe0e81c018076a16036d9b548c4cc649de241fa27d8d9ca6f85ab/sqlalchemy-2.0.44-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2b61188657e3a2b9ac4e8f04d6cf8e51046e28175f79464c67f2fd35bceb0976", size = 3255353, upload-time = "2025-10-10T15:35:31.221Z" },
1204
+ { url = "https://files.pythonhosted.org/packages/b9/96/c6105ed9a880abe346b64d3b6ddef269ddfcab04f7f3d90a0bf3c5a88e82/sqlalchemy-2.0.44-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b87e7b91a5d5973dda5f00cd61ef72ad75a1db73a386b62877d4875a8840959c", size = 3260222, upload-time = "2025-10-10T15:43:50.124Z" },
1205
+ { url = "https://files.pythonhosted.org/packages/44/16/1857e35a47155b5ad927272fee81ae49d398959cb749edca6eaa399b582f/sqlalchemy-2.0.44-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:15f3326f7f0b2bfe406ee562e17f43f36e16167af99c4c0df61db668de20002d", size = 3189614, upload-time = "2025-10-10T15:35:32.578Z" },
1206
+ { url = "https://files.pythonhosted.org/packages/88/ee/4afb39a8ee4fc786e2d716c20ab87b5b1fb33d4ac4129a1aaa574ae8a585/sqlalchemy-2.0.44-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1e77faf6ff919aa8cd63f1c4e561cac1d9a454a191bb864d5dd5e545935e5a40", size = 3226248, upload-time = "2025-10-10T15:43:51.862Z" },
1207
+ { url = "https://files.pythonhosted.org/packages/32/d5/0e66097fc64fa266f29a7963296b40a80d6a997b7ac13806183700676f86/sqlalchemy-2.0.44-cp313-cp313-win32.whl", hash = "sha256:ee51625c2d51f8baadf2829fae817ad0b66b140573939dd69284d2ba3553ae73", size = 2101275, upload-time = "2025-10-10T15:03:26.096Z" },
1208
+ { url = "https://files.pythonhosted.org/packages/03/51/665617fe4f8c6450f42a6d8d69243f9420f5677395572c2fe9d21b493b7b/sqlalchemy-2.0.44-cp313-cp313-win_amd64.whl", hash = "sha256:c1c80faaee1a6c3428cecf40d16a2365bcf56c424c92c2b6f0f9ad204b899e9e", size = 2127901, upload-time = "2025-10-10T15:03:27.548Z" },
1209
+ { url = "https://files.pythonhosted.org/packages/9c/5e/6a29fa884d9fb7ddadf6b69490a9d45fded3b38541713010dad16b77d015/sqlalchemy-2.0.44-py3-none-any.whl", hash = "sha256:19de7ca1246fbef9f9d1bff8f1ab25641569df226364a0e40457dc5457c54b05", size = 1928718, upload-time = "2025-10-10T15:29:45.32Z" },
1210
+ ]
1211
+
1212
  [[package]]
1213
  name = "starlette"
1214
  version = "0.50.0"