A partir du moment ou nous avons une liste de paquetages consolidés, nous pouvons nous en servir pour faire des recherches, mais nous pouvons aussi la sauver sous la forme de table CSVM pour caractériser une installation donnée, et l’utiliser pour diagnostiquer l’installation d’un paquetage. Le module pypkgs fournit quelques fonctions d’interface avec l’écosystème CSVM, pour générer la table, la sauver, la charger et faire une interrogation basée sur le nom d’un paquetage.
1. Exportation d’une liste de paquetages
Prenons le cas d’une liste consolidée plist obtenue avec l’agrégateur pypkgs_plist_merge à partir des listes produites par les méthodes pip, mamba et conda. La fonction pypkgs_plist2csvm_ptr permet la production d’un ilot de données CVM en mémoire et accessible via un pointeur (c dans l’exemple) de type csvm_ptr :
|
1 2 3 |
print("-> export list of packages as csvm_ptr structure\n") c = pypkgs_plist2csvm_ptr(plist, mode='mamba', verb=1) c.csvm_ptr_dump(0,0) |
Le mode 'mamba' signifie que tous les champs renseignés par une méthode mamba ou conda seront dans la table, nous aurons donc une liste d’entêtes ['name', 'ver', 'score', 'build', 'channel', 'loc']. Si mode='simple' nous aurons seulement ['name', 'ver', 'score', 'loc']. La dernière ligne du code permet d’afficher la structure CSVM :
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
csvm_ptr done with 257 rows and 6 cols DUMP: CSVM info { SOURCE CSV META [Done by pypkgs] TITLE_N 0 TITLE Installed packages HEADER_N 6 TYPE_N 6 WIDTH_N 6 0 10 TEXT {name} 1 10 TEXT {ver} 2 10 NUMERIC {score} 3 10 TEXT {build} 4 10 TEXT {channel} 5 50 PATH {loc} DATA_R 257 DATA_C 6 257 6 0 [_openmp_mutex][4.5][4][2_gnu][conda-forge][-] 1 [archspec][0.2.3][196][pyhd8ed1ab_0][conda-forge][C:\Python3\envs\prod\Lib\site-packages\archspec] 2 [attrs][24.3.0][196][pyh71513ae_0][conda-forge][C:\Python3\envs\prod\Lib\site-packages\attrs] ... 254 [zlib][1.3.1][132][h2466b09_2][conda-forge][-] 255 [zstandard][0.23.0][196][py312h7606c53_1][conda-forge][C:\Python3\envs\prod\Lib\site-packages\zstandard] 256 [zstd][1.5.6][4][h0ea2cb4_0][conda-forge][-] BLANK - EMPTY #_REM_ REMARKS } done |
Nous constatons que tous les champs dont remplis par la fusion des colonnes, sauf le champ pdict['loc'] qui n’est pas toujours obtenu à partir d’une résolution via importlib.
Cette table peut être sauvée en fichier CSVM, délimité par des tabulations, via la fonction pypkgs_csvm_ptr2file qui admet en argument un nom de fichier, par exemple :
|
1 2 3 4 |
tfile = file_cleanpath(site_package_buildez + "/install/modules.csvm") print("CSVM file set to [%s]" % (tfile)) status = pypkgs_csvm_ptr2file(c, tfile, verb=1) print("saved package list in csvm database is {%s}" % (status)) |
Ne jamais ou oublier le _cleanpath sur le chemin d’accès du fichier, ainsi le même code sera utilisable sous Ubuntu ou Windows, et en utilisant le slash comme séparateur quel que soit l’OS.
2. Importation et recherche
Il suffit de réaliser l’opération contraire de la précédente via la fonction pypkgs_csvm_file2csvm_ptr qui prends comme argument un nom de fichier et renvoie un objet de type csvm_ptr :
|
1 2 3 4 |
print("+++ get package information using CSVM base\n") tfile = file_cleanpath(site_package_buildez + "/install/modules.csvm") c = pypkgs_csvm_file2csvm_ptr(tfile, verb=1) print("loaded package list from csvm database of %d entries\n" % (c.DATA_R)) |
Une fois que nous avons une table CSVM en mémoire nous pouvons faire une recherche dans la colonne 'name' de la table. Nous utilisons la fonction pypkgs_csvm_file2csvm_ptr et nous pouvons utiliser à nous nos 5 paquetages de test :
|
1 2 3 4 5 6 |
pkg_tests = ["PIL", 'pillow', 'Pillow', 'numpy', 'toto'] for i in range (0, len(pkg_tests), 1): print("-> package [%s]" % (pkg_tests[i])) pdict = pypkgs_pkg_search_csvm_ptr(c, pkg_tests[i], verb=1) print(pdict) print() |
Sans oublier de clôturer l’ensemble par un nettoyage de l’objet avec c.csvm_ptr_clear(), Python le fait tout seul, mais j’aime bien une programmation vintage. Blague à part, nous pouvons maintenant regarder ce qui s’est passé :
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
-> package [PIL] !package 'PIL' not resolved in CSVM table {'name': 'PIL', 'ver': '', 'loc': '', 'files': [], 'err': '', 'installer': '', 'channel': '', 'score': 0, 'summary': '', 'pythonver': '', 'req': [], 'reqby': [], 'build': ''} -> package [pillow] package 'pillow' found at row 159 in CSVM table {'name': 'pillow', 'ver': '11.1.0', 'loc': '-', 'files': [], 'err': '', 'installer': '', 'channel': 'conda-forge', 'score': 68, 'summary': '', 'pythonver': '', 'req': [], 'reqby': [], 'build': 'py312h078707f_0'} -> package [Pillow] !package 'Pillow' not resolved in CSVM table {'name': 'Pillow', 'ver': '', 'loc': '', 'files': [], 'err': '', 'installer': '', 'channel': '', 'score': 0, 'summary': '', 'pythonver': '', 'req': [], 'reqby': [], 'build': ''} -> package [numpy] package 'numpy' found at row 147 in CSVM table {'name': 'numpy', 'ver': '2.2.1', 'loc': 'C:\\Python3\\envs\\prod\\Lib\\site-packages\\numpy', 'files': [], 'err': '', 'installer': '', 'channel': 'conda-forge', 'score': 196, 'summary': '', 'pythonver': '', 'req': [], 'reqby': [], 'build': 'py312hf10105a_0'} -> package [toto] !package 'toto' not resolved in CSVM table {'name': 'toto', 'ver': '', 'loc': '', 'files': [], 'err': '', 'installer': '', 'channel': '', 'score': 0, 'summary': '', 'pythonver': '', 'req': [], 'reqby': [], 'build': ''} |
Nous constatons que PIL n’est pas résolu, alors qu’il est installé, les paquetages pillow et numpy sont bien détectés, le système ne s’est pas fait avoir sur 'Pillow' ni sur 'toto'. La question est de savoir pourquoi nous n’avons pas de ligne 'PIP' dans la colonne 'name' de la table CSVM. Les commandes pip|mamba|conda list | grep PIP ne donnent rien. Ce qui n’est pas le cas pour pillow (après réalignement) :
(prod) C:\Dev>pip list | grep pillowpillow 11.1.0(prod) C:\Dev>mamba list | grep pillowpillow 11.1.0 py312h078707f_0 conda-forge(prod) C:\Dev>conda list | grep pillowpillow 11.1.0 py312h078707f_0 conda-forge |
Rappelons nous que PIP n’est résolu en mode individuel que via importlib et conda (simple ou json), par exemple la commande conda list PIL --json va nous donner :
|
1 2 3 4 5 6 7 8 9 10 11 12 |
[ { "base_url": "https://conda.anaconda.org/conda-forge", "build_number": 0, "build_string": "py312h078707f_0", "channel": "conda-forge", "dist_name": "pillow-11.1.0-py312h078707f_0", "name": "pillow", "platform": "win-64", "version": "11.1.0" } ] |
Il y a résolution mais dans les données nous n’avons que des chaines 'pillow' et non 'PIL', il en sera de même si on génère une liste au format Json (ou non, cf. exemple précédent). Donc PIL passe vraiment sous les radars.
Dans le cas de paquetages comme PIL, l’utilisation d’une recherche par signature (fichiers ou répertoire) sera plus puissante, car dans l’environnement (prod) nous avons bien un dossier PIL qui inclue les modules d’interface et un dossier pillow-11.1.0.dist-info qui contient les métadonnées concernant le système PIL/pillow.
3. Référentiel
Fonctions du module pypkgs.py pour les tables CSVM (mode liste), en mode abrégé (septembre 2025).
| Fonction | Utilisation |
pypkgs_plist2csv_str |
Convertit une liste de dictionnaires pdict en chaine de caractères au format CSV, utilisant les tabulations comme caractère séparateur par défaut (paramétrable). Toutes les clés du dictionnaire pdict sont prises en compte (colonnes du flot CSV). |
pypkgs_plist2csvm_ptr |
Convertit une liste de dictionnaires pdict en table CSVM, renvoie un objet csvm_ptr. Les champs du dictionnaire pdict sont filtrés selon un schéma (argument mode) 'simple' ou 'mamba' pour limiter le nombre de colonnes dans la table CSVM résultante. |
pypkgs_csvm_ptr2file |
Interface à csvm_ptr_csvm2file (du module buildez.parsers.csvm) utilisée pour convertir en chaines de caractères toutes les données de la table CSVM puis sauver la structure csvm_ptr dans un fichier. |
pypkgs_csvm_file2csvm_ptr |
Interface à csvm_ptr_read_csvm (du module buildez.parsers.csvm) utilisée pour lire un fichier CSVM et convertir les données de type string dans le type correspondant à la colonne (ex: scores convertis en entiers). |
pypkgs_pkg_search_csvm_ptr |
A partir d’un objet csvm_ptr et d’un nom de paquetage, la fonction recherche si ce nom est présent dans la colonne 'name' de la table CSVM. Renvoie un dictionnaire pdict vide (résultant de l’initialisation par pypkgs_init_pdict) ou renseigné si le nom de paquetage est présent dans la table. |
4. Conclusion
La génération d’un fichier CSVM à partir de la liste de paquetages citée comme exemple et la recherche d’un nom dans le fichier sont des opérations quasi instantanées (0.01 s de la conversion en csvm_ptr à la sauvegarde du fichier inclus). Nous avons maintenant la possibilité d’avoir une base de paquetages, par environnement ou par machine, qui pourrait être centralisée avec l’ajout de métadonnées et une fusion de données. Il y a encore quelques insuffisances avec des paquetages particuliers, mais qui peuvent être corrigées si on connait le nom du paquetage. Dans ce cas une résolution par signature peut amener un plus et être limitée (car lente) aux paquetages problématiques.