Services métier¶
Vue d'ensemble de la couche services et exemples de composabilité Python. Les services sont la source de vérité des opérations métier — la CLI, l'API web et les importers les réutilisent pour ne jamais dupliquer la logique des invariants.
Organisation¶
src/archives_tool/api/services/
├── _erreurs.py # Hub erreurs métier + helpers
├── fonds.py
├── collections.py
├── items.py
├── collaborateurs_fonds.py
├── dashboard.py # Composeurs pour pages web/CLI
├── preferences.py # PreferencesAffichage
├── sources_image.py # Résolution IIIF Nakala / DZI / aperçu
├── tri.py # Listage[T] générique (tri + pagination)
└── ...
Chaque service expose typiquement :
- un formulaire Pydantic pour les entrées (par ex.
FormulaireFonds,FormulaireItem,FormulaireCollection) ; - des fonctions CRUD (
creer_X,lire_X_par_cote,modifier_X,supprimer_X,lister_X) ; - des erreurs métier nommées (
FondsIntrouvable,CollectionIntrouvable,FormulaireInvalide,OperationCollectionInterdite, …).
Helpers partagés¶
services/_erreurs.py
expose :
- bases d'erreurs (
EntiteIntrouvable,FormulaireInvalide,OperationInterdite) — toutes les erreurs métier en héritent ; - helpers de validation (
chaine_ou_none,PATTERN_COTE,valider_cote).
Composabilité Python¶
Vous pouvez utiliser les services directement depuis du code Python sans passer par la CLI ou l'API web. Quelques exemples courants :
Lire un fonds et ses items¶
from sqlalchemy import select
from archives_tool.api.services.fonds import lire_fonds_par_cote
from archives_tool.db import creer_engine, creer_session_factory
from archives_tool.models import Item
engine = creer_engine("data/archives.db")
factory = creer_session_factory(engine)
with factory() as db:
fonds = lire_fonds_par_cote(db, "HK")
items = list(
db.scalars(select(Item).where(Item.fonds_id == fonds.id))
)
for item in items:
print(item.cote, item.titre)
Composer une vue de page (utilisée par CLI montrer et l'UI web)¶
from archives_tool.api.services.dashboard import composer_page_item
from archives_tool.api.services.fonds import lire_fonds_par_cote
from archives_tool.api.services.items import lire_item_par_cote
with factory() as db:
fonds = lire_fonds_par_cote(db, "HK")
item = lire_item_par_cote(db, "HK-001", fonds.id)
page = composer_page_item(db, item)
print(f"Item dans {len(page.collections)} collection(s)")
for col in page.collections:
print(f" - {col.titre} ({col.type_collection})")
Créer un fonds + items via les services¶
from archives_tool.api.services.fonds import (
creer_fonds, FormulaireFonds,
)
from archives_tool.api.services.items import (
creer_item, FormulaireItem,
)
with factory() as db:
fonds = creer_fonds(db, FormulaireFonds(
cote="TEST", titre="Fonds test",
))
# La collection miroir est créée automatiquement (INV1).
# creer_fonds commit la transaction lui-même.
item = creer_item(db, FormulaireItem(
fonds_id=fonds.id,
cote="TEST-001",
titre="Item de test",
))
# L'item est ajouté automatiquement à la miroir (INV6).
# creer_item commit aussi.
Gérer les erreurs métier¶
from archives_tool.api.services.fonds import (
FondsIntrouvable, lire_fonds_par_cote,
)
try:
fonds = lire_fonds_par_cote(db, "INCONNU")
except FondsIntrouvable:
print("Pas trouvé.")
Les erreurs métier sont nommées et hiérarchisées. Captez-les
explicitement plutôt qu'Exception générique.
Conventions¶
Les services ne font jamais :
- d'
INSERT/UPDATE/DELETEbrut hors d'une fonction CRUD documentée ; - d'écriture sur le système de fichiers (réservé à
files/,derivatives/,renamer/).
Les services font toujours :
- valider les entrées via Pydantic (formulaires) ;
- lever des erreurs métier nommées (pas
Exceptiongénérique) ; - respecter les invariants en une seule transaction
(
creer_fondscrée le fonds + sa miroir + commit ; idem pourcreer_itemqui ajoute aussi l'entréeItemCollection). Conséquence : appeler un service exécute une opération atomique complète. Pour composer plusieurs services dans une même transaction, il faut désactiver explicitement le commit via le paramètre kwarg correspondant — ou réécrire la logique dans un nouveau service.
Voir aussi¶
- Modèle de données — tables, invariants, FK.
- Tests — comment les invariants sont validés.
- Code source :
src/archives_tool/api/services/.