legi.py icon indicating copy to clipboard operation
legi.py copied to clipboard

Abstraire legi.py pour gérer d’autres bases juridiques

Open Seb35 opened this issue 6 years ago • 18 comments

Aujourd’hui, j’ai assisté à un colloque sur la révision constitutionnelle de 2008 qui a, entre autres, vu l’apparition de la QPC. J’ai donc logiquement adapté (rapidement) legi.py à la base CONSTIT.

Pour information, il y a eu (jusqu’au 14 mars 2018), et sauf erreur de programmation (possible quoique les résultats semblent cohérents), 601 QPC au rythme de 70 à 100 par an depuis 2010, avec comme résultats : 306 conformité, 79 non-conformité, 76 conformité avec réserves, 37 non conformité totale + effet différé, puis de nombreux autres statuts.

Cette issue (ambitieuse) se propose de modifier en profondeur legi.py pour que ça puisse être adapté relativement facilement à d’autres bases (il y en a désormais une vingtaine fournies par la DILA). Chaque base a une structure propre même si une structure commune peut être dégagée. En premier inventaire (et pour ce que j’en ai étudié), les structures communes sont :

  • utilisation du XML
  • utilisation d’ID
  • rangement des sous-dossiers par ID
  • mécanisme de mise à jour : Freemium initial + màj légères avec nouvelle version du fichier et liste de suppression (hormis protocole du gouvernement)
  • métadonnées de liens intra-base ou inter-bases

Et, sans être exhaustif, les différences sont :

  • LEGI : sous-dossiers initiaux "code_et_TNC_(en|non)_vigueur/(code|TNC)_en_vigueur"
  • LEGI : utilisation de CID pour regrouper l’appartenance à un même texte dans différentes vigueurs regroupés dans des sous-sous-dossiers
  • KALI, JORF : sous-dossiers initiaux "conteneur"
  • JORFSIMPLE : fichier JORFCONT similaire à celui de JORF dossier "conteneur" mais rangé à côté des JORFTEXT dans un sous-sous-dossier JORFCONT
  • JADE : sous-dossiers initiaux "inedit" vs "publie"
  • INCA : top dossier initial "juri" (puis "inca/global" selon l’arborescence classique)
  • INCA : sous-dossiers initiaux "criminelle" vs "sociale"
  • LEGI : sous-dossiers avec les articles
  • schéma XML propres à chaque base

Dans mon idée, les similitudes pourraient être mises en commun dans des fonctions/classes/modules avec une portée limitée à leur fonctionnalité, et les différences pourraient être soit des fichiers de configuration/description soit des classes enfants d’autres classes plus génériques s’il y a des différences qui ne peuvent pas être décrites simplement dans des fichiers de configuration et doivent avoir un aspect programmatique.

Éventuellement, pour être plus ambitieux et générique encore, mais ça sort du champ de la légistique numérique pour entrer dans le champ de l’informatique, il pourrait être créé une librairie qui prend un fichier XML ainsi qu’une table de correspondance XML -> SQL (ou NoSQL au choix) et transfère les données depuis le fichier XML vers la base SQL/NoSQL. Une telle librairie pourrait être un composant d’une librairie legi.py comme décrite ci-dessus (elle ne gèrerait pas par exemple la gestion des fichiers et des dossiers des bases juridiques).

Seb35 avatar Mar 16 '18 13:03 Seb35

J’ai recherché rapidement s’il existait des librairies XML -> SQL, j’ai trouvé :

  • XML2SQL écrit en Perl, plus maintenu depuis 2013
  • XML2SQL écrit en nodejs et non-documenté
  • des convertisseurs spécialisés depuis des dumps XML vers des bases SQL, par exemple pour Joomla ou MediaWiki ou phpMyAdmin

Rien de vraiment générique et en même temps maintenu, rien (de générique) en Python.

Seb35 avatar Mar 16 '18 13:03 Seb35

La proposition d’un programme générique XML -> SQL se rapproche de language de conversion comme :

  • XSLT qui convertit d’un dialecte XML vers un autre dialecte XML, la table de conversion étant écrite en XML avec un schéma XSLT
  • R2RML qui convertit d’une base de données relationnelle vers du RDF, la table de conversion étant écrite en RDF

PS : je fais comme si je connaissais cela :) mais ne connais que les grands principes, je n’ai jamais utilisé ces languages.

Seb35 avatar Mar 16 '18 13:03 Seb35

En fait le language XSLT peut convenir directement, il est possible d’avoir en sortie du texte simple, en l’occurence ici du SQL. Un prototype de template XSLT pour la transformation d’un texte/version/LEGITEXT0000.xml est le suivant :

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="text" omit-xml-declaration="yes" indent="no"/>
    <xsl:template match="TEXTE_VERSION">
        <xsl:value-of select="concat('INSERT( &quot;'
                    ,META/META_COMMUN/ID
                    ,'&quot;, &quot;'
                    ,META/META_COMMUN/NATURE
                    ,'&quot;, &quot;'
                    ,META/META_SPEC/META_TEXTE_VERSION/TITRE
                    ,'&quot; );&#xA;')"/>
    </xsl:template>
</xsl:stylesheet>

Avec xsltproc (paquet Debian du même nom) :

$ xsltproc transform-texte_version-legi-simple.xsl LEGITEXT000031366350.xml
INSERT( "LEGITEXT000031366350", "CODE", "Code des relations entre le public et l'administration" );

C’est donc possible, mais il reste du travail :

  • chercher une bonne librairie Python,
  • gérer les échappements (il faut XSLT 2.0+ pour avoir accès à la fonction replace qui serait bien pratique dans ce cas, xsltproc ne gère que XSLT 1.0),
  • vérifier qu’on peut bien faire toutes les transformations actuelles en XSLT (le language est Turing-complet, mais bon après il faut voir si ça ne complique pas excessivement).

Seb35 avatar Mar 17 '18 17:03 Seb35

Bonjour, j'ai bien pratiqué XSLT "à l'époque", c'est parfait pour transformer un arbre en... un autre arbre.

Par contre c'est assez verbeux et peu lisible, avec peu de fonctions dispos; dès qu'on doit faire des opérations de base sur les chaines genre substring, ca devient très rude :) ou alors il faut ajouter des extensions customs au language, avec un outillage...douteux à l'époque. donc pour générer et maintenir du SQL ça me parait un peu sport :)

Dans les avantages, c'est Turing-complete, donc la transformation est incassable et reproductible, et il y a le XPATH qui est génial et permet de pouvoir naviguer/looper dans un arbre XML dans tous les sens très facilement.

J'ai bien aimé l'approche d' @alexis-thual qui a bossé sur un outil d'ingestion des données XML dans elasticsearch : https://github.com/alexis-thual/parsing-journal-officiel ; cela permet d'insérer le document brut puis d'utiliser tous les pouvoirs d'elastic pour les query/manipuler. Je ne connais pas assez elastic mais l'idée de ne pas gérer la couche de transformation me parait séduisante. Et en bonus il y a une API consommable et accès à tous les plugins elastic :)

Et sinon, pour info, il y a un écosystème assez extraordinaire en JavaScript sur tout ce qui est xml/json/streams, traitement du texte, du language, conversions de formats etc... avec aussi l'avantage d'avoir beaucoup d'utilisateurs, ce qui veut dire potentiellement de pouvoir mettre les outils à portée de main de plus de personnes :) A dispo pour en discuter !

S'il faut faire du SQL, la conversion XML->SQL avec du JS serait triviale, je peux faire un poc si ca vous intéresse.

revolunet avatar Mar 17 '18 19:03 revolunet

Utiliser XSLT n'a aucun intérêt, ça ne ferait que ralentir la conversion et rendre le code moins lisible.

Réécrire legi.py en JavaScript est évidemment hors de question, ce ne serait qu'une perte de temps.


@Seb35 Les différences dans les arborescences des archives importent peu. Ce qu'il faut analyser ce sont les différences dans les données, pour déterminer s'il faut créer de nouvelles tables dans la BDD, ou adapter les existantes, ou séparer les données dans plusieurs bases SQLite.

Si on regroupe plusieurs bases source dans une même base SQLite alors dans legi.tar2sqlite il faut remplacer le last_update unique par plusieurs valeurs (une pour chaque base source).

Généraliser le module legi.download pour qu'il fonctionne avec toutes les bases est probablement la modification la plus simple, idéal pour une première Pull Request.

Changaco avatar Mar 18 '18 10:03 Changaco

Bonjour, savez-vous s'il existe des outils pour traiter les fichiers KALI ?

revolunet avatar Mar 30 '18 13:03 revolunet

J’avais entendu parler il y a 3 ans d’une startup et/ou d’un projet à ce propos, peut-être chercher du côté d’OpenLaw. De mémoire, c’était plus orienté visualisation.

Seb35 avatar Mar 30 '18 20:03 Seb35

Exact. C'était le projet Contracteo https://www.data.gouv.fr/fr/reuses/contracteo/ (il avait été présenté au meet up du 6 février 2015 dans lequel Archeo Lex avait aussi été présenté par Seb35 https://www.meetup.com/fr-FR/Open-Law/events/220006280/?eventId=220006280 ) .

Le mieux est de contacter directement Melik http://village-legaltech.fr/speakers/melik-boudemagh/ , toujours à Openlaw.fr mais désormais président de http://hercule.co/

Je sais aussi que Lexbase.fr a mobilisé beaucoup d'énergie pour réutiliser les données KALI au début des années 2000, mais je ne sais pas s'ils veulent bien partager leurs secrets, ou même s'ils ont continué à creuser de ce côté. Je me souviens que c'était juste galère d'assurer une simple veille sur les conventions collectives nationales.

cottinstef avatar Apr 05 '18 11:04 cottinstef

Pour info, deux initiatives récentes liées à ceci :

  • @alexis-thual a fait un script (pas sûr qu’il ait été publié) pour décrire la structure des données de différentes bases DILA 1, 2, 3,
  • @eraviart a mis en ligne les différents schémas XML de données de l’Assemblée (un peu hors-sujet par rapport cette issue mais connexe).

Seb35 avatar May 28 '18 13:05 Seb35

Pour compléter le message ci-dessus, les deux scripts qui permettent d'explorer la structure des données se trouvent ici :

Le README du repo en question explique d'ailleurs comment exécuter ces scripts ! :)

alexisthual avatar May 30 '18 08:05 alexisthual

Deux choses relatives à cette issue :

  • j’ai mis à disposition le fichier constit.sqlite mentionné au début téléchargement direct PHPLiteAdmin, et j’ai pushé le code, ça a été fait très rapidement donc il peut y avoir des erreurs
  • je vais me pencher sous peu sur une adaptation peu modificatrice de legi.py et de bonne facture (je vais essayer) pour ajouter une partie de la base JORF, la partie des textes (et sections et articles) ayant une correspondance dans la base LEGI car celle-ci ne contient pas les versions initiales des textes ; j’en aurai besoin pour que Archéo Lex ait les versions initiales notamment des lois qui sortent, puisque les articles de type "texte modificateur/amendement" n’ont pas le texte même des articles mais uniquement du texte comme "A modifié les dispositions suivantes : Crée Code de la santé publique - art. D4111-13-1 (V)" correspondant à l’opération de consolidation présentée sur Légifrance, ce qui n’est pas présentable ni très intéressant, et j’aurai besoin de ces données pour DuraLex pour appliquer les projets/propositions de loi sur les lois en vigueur, actuellement je n’ai réellement que les codes en vigueur.

Seb35 avatar Jan 14 '19 13:01 Seb35

Sur le 2e point, quoiqu’il faille encore vérifier les détails pour une bonne cohabitation entre les lois contenues dans la base JORF avec les lois contenues dans la base LEGI, je pense ajouter :

  • dans la table textes_versions des id commençant par JORFTEXT (il faut que je vérifie si ça n’entre pas en conflit avec les id existants de la base LEGI)
  • dans la table articles des id commençant par JORFARTI
  • dans la table sections des id commençant par JORFSCTA
  • probablement dans la table sommaires les liens entre textes, sections et articles, mais il faut vérifier que ça cohabiterait sans soucis avec ce qu’il y a déjà de la base LEGI

Cela obligera à lire et parser une autre base (concrètement un autre .tar.gz), je pense ajouter un champ supplémentaire dans db_meta pour mentionner la date de dernière mise à jour de cette base. Je n’ai pas encore réfléchi en détails s’il vallait mieux copier le fichier tar2sqlite pour l’adapter à JORF ou alors ajouter des choses dans ce fichier existant.

Seb35 avatar Jan 14 '19 14:01 Seb35

Voici l’exploration préalable des bases de la DILA. On constate que LEGI est quasiment la plus complexe, hormis JORF et KALI qui ont une structure "conteneur" (~sommaire si je comprend bien). Cela n’aborde pas la structure XML mais je ne pense pas que le XML ajoute de la complexité par rapport à ce que fait apparaître l’arborescence (les liens entre les différents fichiers).

Seb35 avatar Jan 17 '19 13:01 Seb35

J’ai implémenté la lecture de la base JORF, j’enverrai prochainement une pull request je vérifie juste que la liste de suppression fonctionne bien (c’est rare dans JORF mais ça arrive). On pourra en discuter sur la pull request, mais contrairement à ce que je disais plus haut, je suis parti sur la création d’une 2e base SQLite, la principale chose à adapter était l’arborescence des fichiers.

Seb35 avatar Jan 21 '19 10:01 Seb35

@Seb35 J'aimerais aussi me lancer dans l'adaptation de legi.py pour gérer la base KALI. Est-ce que tu peux publier ta PR même si le travail n'est pas fini, pour que je ne fasse pas le boulot en double si tu as déjà générisé un peu.

Pour info, jusqu'ici, j'ai travaillé indépendamment de legi.py sur l'extraction des données de KALI pour les mettre dans une base MongoDB et explorer rapidement le contenu : https://github.com/SocialGouv/kali_dumps_scripts.

adipasquale avatar Jan 25 '19 10:01 adipasquale

Voilà la requête d’intégration (je m’essaye à la traduction de pull request).

Pour KALI, j’imagine qu’il suffit d’enregistrer le nom KALI à côté de JORF et LEGI. Toutefois, je n’ai pas ajouté la notion de conteneur présente dans JORF et KALI, je pense que tu peux ajouter une table pour cela.

Seb35 avatar Jan 27 '19 17:01 Seb35

Pour information, j’ai commencé à modifier Archéo Lex pour qu’il lise les deux bases JORF et LEGI (dans deux fichiers SQLite) afin qu’il utilise la base JORF pour la première version d’un texte et la base LEGI pour les versions ultérieures, je publierai sous peu cette modification. Il y a une petite subtilité car seuls les articles "autonomes" (=qui ne sont pas des textes modificateurs) sont réellement consolidés dans LEGI dans le sens que les articles non-autonomes n’affichent que des métadonnées vagues : il n’y a pas de textes modificateurs consolidés. Cela fait qu’une grande partie des lois (hors codes) deviennent de moins en moins lisibles en fonction des nouvelles consolidations car elles sont remplacées par des métadonnées vagues. Mais outre consolider nous-même les textes (ce qui n’est pas non plus infaisable grâce à DuraLex), ça restera ainsi en attendant.

Seb35 avatar Jan 27 '19 17:01 Seb35

Merci @Seb35 je vais regarder ça et essayer sur KALI dans la semaine !

adipasquale avatar Jan 28 '19 08:01 adipasquale