Diagnostics : module pypkgs (mode paquetage)

2. Méthode importlib

C’est la manière la plus rapide de procéder puisqu’on utilise une bibliothèque Python en détournant la finalité du système d’import à notre profit pour chercher les paquetages. La fonction pypkgs_importlib (après un appel à pypkgs_scoring ) va nous donner accès aux champs ‘name’ (nom du paquetage), ‘loc’ (localisation), ‘ver’ (version), ‘summary’ (résumé de la fonction du paquetage), ‘pythonver’ (necessite une certaine version de Python), ‘files’ (fichiers utilisés par le paquetage).

Nous allons utiliser importlib.util, importlib.metadata, importlib.resources pour compléter pdict à partir de plusieurs sources de données. Dans le premier cas, l’utilisation d’importlib.util ne nous permet d’obtenir que le nom du paquetage et sa localisation :

Si le paquetage est résolu, nous obtenons une classe spec qui décrit le module, et nous utilisons une méthode submodule_search_locations pour obtenir la liste des localisations, dont nous prenons la première valeur, qui sera stockée dans pdict['loc'], puis pdict['score'] sera mis à jour avec pypkgs_scoring pour le bit importlib.

submodule_search_locations – A (possibly empty) sequence of strings enumerating the locations in which a package’s submodules will be found (see module.__path__). Most of the time there will only be a single directory in this list … 

Ce exemple montre le mécanisme général, nous utilisons ensuite importlib.metadata (préalablement importé avec  from importlib.metadata import metadata, PackageNotFoundError) pour compléter d’autres champs de pdict et augmenter le score :

Puis enfin, on passe à importlib.ressources pour obtenir une liste des fichiers correspondant à un module :

Puis on retourne le dictionnaire pdict.

Test drive

Ce n’est pas forcément intéressant d’avoir tout le temps les valeurs correspondant aux fichiers, ni au sommaire, c’est pour cela que pypkgs_importlib inclue deux arguments booléens files et meta que l’on peut positionner sur la valeur False. La syntaxe de pypkgs_importlib est :

pypkgs_importlib(pname, pdict={}, files=True, meta=True, verb=0):

Nous allons l’utiliser dans une boucle, avec un jeu de modules sous la forme d’une liste pkg_tests = [« PIL », ‘pillow’, ‘Pillow’, ‘numpy’, ‘toto’].

Et nous allons voir le résultat pour chaque module:

Dans le cas de PIL, nous avons un score de 160, mais nous n’avons accès qu’au nom, localisation et fichiers :

importlib: package 'PIL' resolved with score=160
{'name': 'PIL', 'ver': '', 'loc': 'C:\\Python3\\envs\\prod\\Lib\\site-packages\\PIL', 'files': ['AvifImagePlugin.py', 'BdfFontFile.py', 'BlpImagePlugin.py', 'BmpImagePlugin.py', 'BufrStubImagePlugin.py', 'ContainerIO.py', 'CurImagePlugin.py', 'DcxImagePlugin.py',
...
'_webp.cp312-win_amd64.pyd', '_webp.pyi', '__init__.py', '__main__.py', '__pycache__'], 'err': '', 'installer': '', 'channel': '', 'score': 160, 'summary': '', 'pythonver': '', 'req': [], 'reqby': [], 'build': ''}

Dans le cas de pillow (interface pour PIL) nous avons un score de 64, avec le nom, la version, le sommaire, la version de Python, mais pas les fichiers :

importlib: package 'pillow' resolved with score=64
{'name': 'pillow', 'ver': '11.3.0', 'loc': '', 'files': [], 'err': '', 'installer': '', 'channel': '', 'score': 64, 'summary': 'Python Imaging Library (Fork)', 'pythonver': '>=3.9', 'req': [], 'reqby': [], 'build': ''}

Dans le cas de Pillow, le paquetage résolu est 'pillow', nous avons donc le même résultat et score que pour l’exemple précédent, le système semble tolérant à la casse. 
Dans le cas de numpy, avec un score de 224 nous avons quelque chose de très complet :

importlib: package 'numpy' resolved with score=224
{'name': 'numpy', 'ver': '2.3.3', 'loc': 'C:\\Python3\\envs\\prod\\Lib\\site-packages\\numpy', 'files': ['char', 'conftest.py', 'core', 'ctypeslib', 'doc', 'dtypes.py', 'dtypes.pyi',
...
'_pytesttester.pyi', '_typing', '_utils', '__config__.py', '__config__.pyi', '__init__.cython-30.pxd', '__init__.pxd', '__init__.py', '__init__.pyi', '__pycache__'], 'err': '', 'installer': '', 'channel': '', 'score': 224, 'summary': 'Fundamental package for array computing in Python', 'pythonver': '>=3.11', 'req': [], 'reqby': [], 'build': ''}

Et dans le cas du paquetage toto nous n’avons rien et un score de zéro, ce qui est rassurant.

Nous voyons donc qu’il est difficile de prévoir ce que l’on va pouvoir obtenir comme information, c’est paquetage dépendant. En l’état la méthode importlib ne donne pas accès au canal de distribution, ni au build. Il serait peut être possible d’utiliser distribution comme metadata (cf. from importlib.metadata import distribution, PackageNotFoundError) mais finalement il est plus logique d’utiliser une méthode basée sur pip, mamba ou conda pour obtenir ce type d’informations. L’intérêt de cette méthode est qu’elle est quasiment instantanée.

Liens et lectures
Retour en haut