Python en entreprise avec la rétro-ingénierie
Apr 15, 2024La rétro-ingénierie a pour but d’expliquer le fonctionnement d’un système et de la documenter. Dans le contexte de la donnée, elle a plusieurs objectifs :
- Faciliter le transfert de connaissance en mettant à jour les spécifications techniques,
- Constituer un référentiel permettant de mieux estimer la charge de travail à venir sur les projets d’évolution,
- Commenter le code utilisé pour préparer à son intégration ou son évolution
- etc.
Nous allons voir dans cet article comment Python est utilisé comme outil de rétro- ingénierie, et contribue à documenter les développements et l'architecture des projets IT.
Recenser les tables sources utilisées pour alimenter le Datamart
Lors d’un projet de migration comme lors d’un déménagement c’est l’occasion de faire le tri et d’identifier tous les tables obsolètes qui prennent de l’espace de stockage.
Python s’avère pratique pour analyser les flux ETL qui s’opère dans une base de données SQL, grâce à l’extraction des procédures stockés dans lesquelles sont contenues ces informations. En effet actuellement il n’existe pas de fonctionnalité native « intelligente » dans les SGBD permettant de lister les tables manipulées dans des blocs de code SQL.
Avec Python l’approche est la suivante :
- Extraire le code SQL de la base de données
- Le « nettoyer » en supprimant le code obsolète et les commentaires
- Récupérer le nom des tables
Ces étapes sont détaillées dans la suite de l’article.
Extraire le code SQL de la base de données
Une des librairies utilisées pour interagir avec une instance SQL est pyodbc. Son utilisation est assez simple et commence par la saisie des informations de connexion comme ci-dessous :
import pyodbc nom_server = '760YFX3' database = 'BI_DW_ParchAndPosey' cnxn = pyodbc.connect(r'Driver={SQL Server};Server='+nom_server+';Database='+database+';Trusted_connection=yes;') cursor = cnxn.cursor() cursor.execute("SELECT OBJECT_DEFINITION(object_id) as ma_procedure FROM sys.procedures")
Puis récupérer le code sous forme de liste de chaîne decaractère (String) grâce à une boucle with():
procs=[] while 1: row = cursor.fetchone() if not row: break # pour chaque ligne on assemble
procs.append(row.ma_procedure)
Ainsi chaque élément de la liste correspondra à une ligne retournée par la requête SQL de type SELECT.
En procédant de cette manière, on pourra travailler en local sans passer par le système de gestion de base de données. On pourra vérifier la bonne intégration avec l’instruction suivante :
len(procs)
Et en comparant le résultats en python avec le nombre de ligne en sortie de la requête SQL.
Préparation des données
Cette étape fait référence à plusieurs transformations permettant d’identifier les tables sources et uniquement celles-ci avec une expression régulière.
- La 1ère transformation concerne le découpage des éléments dans la liste. En effet actuellement chaque élément correspond à une procédure alors qu’il est plus naturel d’utiliser le format d’origine : ligne par ligne. Pour cela il nous faut lier l’ensemble des éléments puis de nouveau les séparer avec les instructions suivantes Python :
# lier chaque élément de la liste en un seul élement de type String concat = ''.join(procs) # séparer chaque élément lors d'un retour à la ligne lines= concat.split('\r\n')
- Ensuite il va nous falloir différencier les lignes commentaires des lignes de codes, afin de ne pas prendre en compte dans le recensement des tables le code obsolète ou « dead code ».
requete_sans_commentaires=[] for line in lines: if ("--" not in line): w = line
requete_sans_commentaires.append(w)
- Enfin nous devons retirer les caractères qui risquent de faire des doublons lors du recensement comme la virgule (« , » ) et le point-virgule (« ; » )
# Parcours de la liste pour supprimer la virgule puis redécouper requete_finale = [ligne.replace(",", "").replace(";", "") for ligne in requete_sans_commentaires]
Récupération du nom des tables
Pour identifier le nom des tables nous devons choisir l’expression régulière qui couvre l’ensemble des chaînes de caractère contenant l’information indiquant une table. Les valeurs concernées sont sous la forme :
[Schema].[table] ou [Schema].[table].[colonne]
Donc si nous utilisons la chaîne de caractère « [Schema]. » pour identifier les éléments.
i = 0 Schema = 'ParchAndPosey.dbo.' liste_table = [] while i<len(requete_finale): # Si une partie de la chaîne de caractère commence par '[ParchAndPosey.dbo.].', alors on récupère cette ligne if (Schema in requete_finale[i]):
liste_table.append(requete_finale[i].split(Schema,1)[1].split(' ',1)[0]) i=i+1
La fonction « split() » suivie des crochets (« [ ] ») permet de ne pas récupérer les éléments avant et après le noms de la tables.
Enfin il est possible d’utiliser la fonction native set() afin de supprimer les doublons
# suppression des doublons sam_list = list(set(liste_table)) print('\n'.join(sam_list))
Ainsi toutes les tables listées en sortie de ce script sont celles utilisés dans les procédures de la base 'ParchAndPosey’.
Comparaison entre l’utilisation d’SQL et de python
Certains concepts de programmation comme l'approche procédural sont similaires entre Python et SQL, donc libre à vous de chercher à obtenir le même résultat sur un SGBD comme SQL server. Nous avons choisis Python dans cet article pour la simplicité de ce langage et sa large utilisation dans les domaines de la data (machine learning, datavisualisation, etc.).
En effet traiter des informations de type texte en utilisant python offre plus de simplicité que SQL sur les points suivant:
- Manipuler les données texte, grâce aux fonctions s’appliquant aux listes de chaîne de caractère,
- Incrémenter des boucles comme for() ou with() dont l’implémentation est similaire aux autres langages de programmation,
- Appliquer la récursivité en prenant en compte les différentes couches de bases de données,
- Travailler en local sans solliciter la base de données SQL
Pour conclure : au-delà de la praticité du langage python pour récupérer dynamiquement une information, l’approche rétro-ingénierie est primordiale car elle permet de gagner en efficacité sur les projets IT.