Site citoyen non officiel — sans lien avec l'Assemblée nationale ni le Conseil constitutionnel.

Comment ce chiffre est produit : Engagements de responsabilité (49.3)

Chaque étape, de la source primaire jusqu'au chiffre affiché sur la page Engagements de responsabilité (49.3). Les volumes sont lus dans la base au moment de l'affichage ; le code est celui qui tourne sur le serveur (version 4aabd6c).

Parcours des données

  1. 1. Fichiers sources3 fichiers publiés par l'Assemblée nationale et la DILA, téléchargés avec leur date de publication et contrôlés par leur empreinte MD5.
  2. 2. Données brutes versionnéesAN_DOSSIERS : 35 600 enregistrements courants (35 725 versions conservées).
  3. 3. Lecture et transformationengagements 49.3 lus dans les dossiers : 32retenus (15e à 17e législature) : 32dont textes budgétaires : 29Corrections justifiées : 0 (détail).
  4. 4. CalculMéthode I1 version 1 (définition), par législature, année parlementaire et session.
  5. 5. Résultats figés82 valeurs, calculées le 6 novembre 2026 (lot 400c1859), servies par l'API (/api/indicateurs/I1).
  6. 6. AffichageGraphiques et tableaux de la page Engagements de responsabilité (49.3), avec la source de chaque élément.

Fichiers sources

Dernière version intégrée de chaque fichier
SourceFichierLégislaturePublié leCollecté leMD5 (publié / calculé)
AN_DOSSIERSDossiers_Legislatifs_XV.json.zip1509/06/202206/11/202608f79aa683f73dbfe43b96c3eff0a64d
08f79aa683f73dbfe43b96c3eff0a64d
AN_DOSSIERSDossiers_Legislatifs.json.zip1628/06/202406/11/2026e7eb837f9ff3128e3dcbcdeddf6a12d4
e7eb837f9ff3128e3dcbcdeddf6a12d4
AN_DOSSIERSDossiers_Legislatifs.json.zip1706/11/202606/11/2026c3f6a8e8a40d8fe716a8ceee5f5129e1
c3f6a8e8a40d8fe716a8ceee5f5129e1

Code du calcul

Fonctions exécutées par le serveur pour produire ce chiffre, dans l'ordre : lecture des sources, puis calcul. Le texte est extrait du programme en cours d'exécution (version 4aabd6c).

Transformation.engagements_et_motions — donnees.transformation, lignes 432-513
def engagements_et_motions(self):
    # Dossier du texte : dossier (hors procédure 13) qui contient un acte « …-DGVT » de même n° de texte.
    hote = {}
    for uid, (_, dp) in self.dossiers_json.items():
        if (dp.get("procedureParlementaire") or {}).get("code") == an.PROCEDURE_ENGAGEMENT:
            continue
        for a in an.actes(dp.get("actesLegislatifs")):
            if (a.get("codeActe") or "").endswith("-DGVT") and a.get("texteAssocie"):
                hote[an.numero_texte(a["texteAssocie"])] = (uid, a["codeActe"].split("-")[0])

    motions_brutes = []  # (motion json, dossier uid, engagement ou None, structurel ?)
    engagements = []
    for uid, (brut, dp) in self.dossiers_json.items():
        if (dp.get("procedureParlementaire") or {}).get("code") != an.PROCEDURE_ENGAGEMENT:
            continue
        tous = an.actes(dp.get("actesLegislatifs"))
        eng_actes = [a for a in tous if an.est_engagement_493(a)]
        imbriquees = {}
        for a in eng_actes:
            jour = _jour(a["dateActe"])
            texte_uid, lecture = hote.get(an.numero_texte(a.get("texteAssocie")), (None, ""))
            dossier_texte = self.dos.get(texte_uid) if texte_uid else None
            if dossier_texte is None:
                self.rapport.alerte(f"Engagement {a['uid']} : dossier du texte introuvable")
            e = Engagement493(
                uid=a["uid"],
                date=jour,
                declaration=a.get("texteAssocie") or "",
                dossier_engagement=self.dos[uid],
                dossier_texte=dossier_texte,
                lecture=lecture,
                budgetaire=bool(
                    dossier_texte and dossier_texte.procedure_code in an.PROCEDURES_BUDGETAIRES
                ),
                session=self.session(jour),
                # Source : page du dossier d'engagement sur le site de l'Assemblée
                **_trace(brut, a["uid"], an.url_dossier(dp["legislature"], uid)),
            )
            engagements.append(e)
            for m in an.actes(a.get("actesLegislatifs")):
                if m.get("codeActe") == an.ACTE_MOTION:
                    imbriquees[m["uid"]] = e
        for m in tous:
            if m.get("codeActe") != an.ACTE_MOTION:
                continue
            if m["uid"] in imbriquees:
                motions_brutes.append((brut, m, uid, imbriquees[m["uid"]], ModeRattachement.STRUCTUREL))
            elif eng_actes:  # 15e : motion non imbriquée dans un dossier d'engagement
                e = next(x for x in engagements if x.uid == eng_actes[0]["uid"])
                motions_brutes.append((brut, m, uid, e, ModeRattachement.DOSSIER_DATE))
            else:
                motions_brutes.append((brut, m, uid, None, ModeRattachement.SANS_OBJET))
    Engagement493.objects.bulk_create(engagements)
    self.rapport.comptes["engagements_49_3"] = len(engagements)

    motions = []
    for brut, m, dossier_uid, eng, mode in motions_brutes:
        vote = an.vote_de_motion(m)
        ref = (vote.get("voteRefs") or {}).get("voteRef")
        scrutin = self.scr.get(ref) if ref else None
        motions.append(
            MotionCensure(
                identifiant=m.get("texteAssocie") or "",
                dossier=self.dos[dossier_uid],
                date_depot=_jour(m.get("dateActe")),
                alinea=3 if eng else 2,
                statut=MotionCensure.Statut.RETIREE
                if m.get("dateRetrait")
                else MotionCensure.Statut.NON_VOTEE,
                engagement=eng,
                mode_rattachement_engagement=mode,
                scrutin=scrutin,
                mode_rattachement_scrutin=ModeRattachement.VOTE_REF
                if scrutin
                else ModeRattachement.SANS_OBJET,
                **_trace(brut, m["uid"], self.dos[dossier_uid].url_source),
            )
        )
    self._rattacher_scrutins(motions)
    MotionCensure.objects.bulk_create(motions)
    self.rapport.comptes["motions"] = len(motions)
    self.rapport.comptes["motions_votees"] = sum(m.statut == "votee" for m in motions)
periodes — indicateurs.calcul, lignes 73-81
def periodes(jour: dt.date, legislature: int) -> list[tuple[str, str]]:
    annee = annee_parlementaire(jour)
    return [
        (ResultatIndicateur.PeriodeType.LEGISLATURE, str(legislature)),
        (ResultatIndicateur.PeriodeType.ANNEE_PARLEMENTAIRE, annee),
        (ResultatIndicateur.PeriodeType.SESSION, f"{annee}/{type_session(jour)}"),
        (ResultatIndicateur.PeriodeType.LEGISLATURE_ANNEE, f"{legislature}/{annee}"),
        (ResultatIndicateur.PeriodeType.LEGISLATURE_SESSION, f"{legislature}/{annee}/{type_session(jour)}"),
    ]
_compter — indicateurs.calcul, lignes 93-103
def _compter(elements, cle_legislature, cle_date, ventilations) -> dict:
    """{(periode_type, periode): Counter(ventilation)}"""
    comptes = defaultdict(Counter)
    for e in elements:
        leg = cle_legislature(e)
        if leg not in LEGISLATURES_JALON:
            continue
        for periode in periodes(cle_date(e), leg):
            for v in ventilations(e):
                comptes[periode][v] += 1
    return comptes
calculer() — bloc I1 — indicateurs.calcul
# I1 — engagements 49.3
engagements = list(Engagement493.objects.select_related("dossier_engagement"))
ajouter(
    "I1",
    _compter(
        engagements,
        lambda e: legs.a_la_date(e.date),
        lambda e: e.date,
        lambda e: ["total", "budgetaire" if e.budgetaire else "autres"],
    ),
)
textes = defaultdict(set)
for e in engagements:
    leg = legs.a_la_date(e.date)
    if leg in LEGISLATURES_JALON and e.dossier_texte_id:
        for periode in periodes(e.date, leg):
            textes[periode].add(e.dossier_texte_id)
for (ptype, periode), ids in textes.items():
    resultats.append(
        ResultatIndicateur(
            definition=defs["I1"],
            periode_type=ptype,
            periode=periode,
            ventilation="textes_distincts",
            valeur=len(ids),
            numerateur=len(ids),
            lot=lot,
        )
    )