4. Réagir, et s'en aller
Notre extension doit savoir qu’une affaire vient d’être perdue, pour vérifier que quelqu’un a
nommé le gagnant. Elle ne va pas le demander à pipeline. Elle écoute.
L’écoute
"""Reacting to ``pipeline`` without importing it.
The extension needs to know when an opportunity is lost. It does NOT call into``pipeline`` to find out: it listens.
That is the whole difference between extending a module and forking it. Theevent is a public fact; the code behind it is not."""
from kewos.events import subscribe
#: Emitted by the kernel on every write. We filter on the model rather than ask#: `pipeline` for a dedicated event: a module we extend owes us nothing._WRITE_EVENT = "record.updated"
def note_the_winner(event: Event) -> None: """When an opportunity is marked lost, check that a winner was named.""" payload = event.payload or {} if payload.get("model") != "pipeline_lead": return record = payload.get("record") if record is None or getattr(record, "state", None) != "lost": return if getattr(record, "rivals_won_by_id", None) is None: _log.info("opportunity %s was lost with no competitor named", record.id)
def register_listeners() -> None: """Subscribe on module load.""" subscribe(_WRITE_EVENT, note_the_winner)C’est tout le contrat. Le noyau émet record.updated sur toute écriture ; nous filtrons
sur le modèle. Nous ne réclamons pas à pipeline un événement dédié, parce qu’un module qu’on
étend ne nous doit rien : ce qu’il publie, il le publie pour tout le monde.
Il ne corrige rien, il le dit
Le gestionnaire n’écrit pas. Il journalise l’omission pour qu’une revue la voie. Remplir le champ à la place de l’humain serait deviner, et empoisonnerait exactement le rapport que ce module existe pour produire : un gagnant inventé compte comme un gagnant.
Le même besoin, sans code
Ce que fait ce fichier peut aussi se poser dans le moteur visuel, et se livrer avec le module, comme le fait le premier parcours à l’étape « Automatiser ». La question à trancher est toujours la même : cette règle est-elle la vôtre, ou celle du client ? Ce qui relève de votre jugement de conception va dans le code ; ce que le client voudra changer sans vous va dans un flux.
Se désinstaller sans rien laisser
C’est le test qui dit si vous avez étendu ou forké. Désinstallez pipeline_rivals :
rivals_competitordisparaît : c’était notre table ;pipeline_leadperd deux colonnes contribuées, et rien d’autre ;- la rustine de vue s’en va, et la vue de
pipelineredevient ce qu’elle était, parce qu’elle n’a jamais été remplacée ; - l’abonnement disparaît avec le processus.
Rien de tout cela n’a demandé de code de désinstallation. C’est la conséquence directe des trois choix des étapes précédentes : notre modèle porte notre préfixe, nos champs aussi, et notre écran est une rustine.
Reprenez maintenant l’inverse. Si vous aviez copié pipeline_lead.form.json pour y glisser
deux champs, la désinstallation vous laisserait la copie, figée à la version où vous l’avez
prise.
L’extension finie, à télécharger
- pipeline_rivals-0.1.0.kws (7 Ko) — le module de ce parcours, avec ses deux rustines de vue, son écouteur et ses données de démo.
74af7d7e9382e16b26815412a4f29d6e608a961180f416feabf0882c14f2619f pipeline_rivals-0.1.0.kwssha256sum pipeline_rivals-0.1.0.kws
kewos module install pipeline_rivals-0.1.0.kws \ --database-url "$KEWOS_DATABASE_URL" \ --modules-root "$KEWOS_MODULES_ROOT" \ --allow-unsignedkewos reconcile --confirmpipeline doit être installé et activé avant, sinon le gel du registre s’arrête sur la
dépendance manquante, en la nommant. La marche complète, et pourquoi le paquet n’est pas
signé, sont expliquées à la dernière étape du premier parcours,
Livrer.
La liste de contrôle
Avant de livrer une extension, ces cinq réponses doivent être « oui » :
grep -r "import modules\." mon_module/ne renvoie rien.- Tout ce que j’ai créé porte le préfixe de mon module.
- Mes champs ajoutés sont
nullable=True. - Mes écrans sur les modèles d’autrui sont des
*.patch.json, pas des vues complètes. - Mon manifeste déclare
dependssur ce que j’étends.
Et ensuite
Vous savez construire un module et en étendre un. Ce qui reste est le même travail qu’ailleurs : l’emballer et l’installer, décrit à la dernière étape du premier parcours, Livrer.