Empaqueter des modules Python avec des roues


  • Français


  • Tous ceux qui travaillent avec Python depuis un certain temps ont peut-être déjà découvert des packages. Dans la terminologie Python, les packages (ou packages de distribution) sont des collections d’un ou plusieurs modules Python qui fournissent des fonctionnalités spécifiques. Le concept général est comparable aux bibliothèques dans d’autres langues. Certaines particularités des packages Python rendent leur traitement différent.

    Pip et PyPi

    Le moyen le plus courant d’installer un package Python tiers consiste à utiliser le programme d’installation du package pépin, fourni par défaut. L’index des packages Python (PyPi) est le serveur central pour les packages de toutes sortes et la source par défaut pour pip. Les packages Python contiennent des fichiers qui spécifient le nom du package, sa version et d’autres méta-informations. Sur la base de ces fichiers, PyPi sait comment classer et indexer un package. De plus, ces fichiers peuvent inclure des instructions d’installation que pip traite.

    Source et distribution binaire

    Les modules Python sont distribués dans plusieurs formats, chacun avec des avantages et des inconvénients. En général, les formats peuvent être divisés en deux groupes.

    Répartition des sources (sdist)

    Les distributions de source sont définies dans PEP 517 et sont des archives tar compressées avec le fichier se terminant *.tar.gz. L’archive contient tous les fichiers source liés au package et les instructions d’installation. Une distribution source a souvent des dépendances à un système de construction comme distutils ou alors outils de configuration qui provoquent l’exécution de code lors de l’installation. L’exécution de code (arbitraire) lors de l’installation peut soulever des problèmes de sécurité.

    Dans le cas d’une extension Python C/C++, une distribution source contient des fichiers C/C++ simples. Ceux-ci doivent être compilés lors de l’installation, donc une chaîne d’outils C/C++ appropriée doit être présente.

    Distributions construites (bdist)

    En revanche, vous pouvez souvent utiliser une distribution construite telle quelle. L’idée derrière les distributions construites est de fournir un format de package sans introduire de dépendances supplémentaires. En ce qui concerne l’extension Python C/C++, une distribution construite fournit des binaires prêts pour la plate-forme de l’utilisateur.

    Le format de distribution construit le plus largement utilisé est le Roue Pythonspécifié dans PEP 427.

    Roues Python

    Les roues sont des archives ZIP avec le fichier se terminant .whl. Une roue peut contenir des binaires, des scripts ou des fichiers Python simples. Si une roue contient des binaires d’un module d’extension C/C++, elle l’indique en incluant sa plate-forme cible dans son nom de fichier. Fichiers Python purs (.py) sont compilés en code binaire Python (.pyc) lors de l’installation de la roue.

    Si vous essayez d’installer un paquet à partir de PyPi en utilisant pip, il choisit toujours une roue Python plutôt qu’une distribution source. Cependant, lorsque pip ne trouve pas de roue compatible, il tente de récupérer la distribution source à la place. En tant que mainteneur de paquet, c’est une bonne pratique de fournir les deux formats sur pip. Pour un utilisateur de package, l’utilisation de roues sur les distributions source est avantageuse en raison du processus d’installation plus sûr, de leur taille plus petite et, par conséquent, d’un temps d’installation plus rapide.

    Pour s’adresser à un large éventail d’utilisateurs, le responsable du paquet doit proposer des roues pour différentes plates-formes et versions Python.

    Dans l’un de mes articles précédents, Écrire un module d’extension C++ pour Python, j’ai montré comment créer une extension Python C++ pour l’interpréteur CPython. Vous pouvez réutiliser l’article code d’exemple pour construire votre première roue.

    Définir la configuration de construction avec setuptools

    Le référentiel de démonstration contient les fichiers suivants, qui contiennent des méta-informations et une description du processus de génération :

    pyproject.toml

    [build-system]
    requires = [
        "setuptools>=58"
    ]
    
    build-backend = "setuptools.build_meta"

    Ce fichier est le successeur du setup.py puisque PEP 517 et PEP 518. Ce fichier est en fait le point d’entrée du processus de conditionnement. La clé build-backend indique à pip d’utiliser setuptools comme système de construction.

    setup.cfg

    Ce fichier contient les métadonnées statiques et immuables du package :

    [metadata]
    name = MyModule
    version = 0.0.1
    
    description = Example C/C++ extension module
    long_description = Does nothing except incremention a number
    license = GPLv3
    classifiers = 
        Operating System::Microsoft
        Operating System::POSIX::Linux
        Programming Language::C++

    setup.py

    Ce fichier définit le processus de construction générique pour le module Python. Toutes les actions qui doivent être effectuées au moment de l’installation vont ici.

    Pour des raisons de sécurité, ce fichier ne doit être présent qu’en cas d’absolue nécessité.

    from setuptools import setup, Extension
    
    MyModule = Extension(
                        'MyModule',
                        sources = ['my_py_module.cpp', 'my_class_py_type.cpp'],
                        extra_compile_args=['-std=c++17']
                        )
    
    setup(ext_modules = [MyModule])

    Cet exemple de package est en fait une extension Python C/C++, il nécessite donc une chaîne d’outils C/C++ sur le système de l’utilisateur pour être compilé. Dans l’article précédent, j’ai utilisé CMake pour générer la configuration de construction. Cette fois, j’utilise setuptools pour le processus de construction. J’ai rencontré des difficultés lors de l’exécution de CMake dans un conteneur de construction (je reviendrai sur ce point plus tard). Les setup.py contient toutes les informations requises pour construire le module d’extension.

    Dans cet exemple, setup.py répertorie les fichiers source impliqués et certains arguments de compilation (facultatifs). Vous pouvez trouver une référence à la construction setuptools dans le Documentation.

    Processus de construction

    Pour démarrer le processus de construction, ouvrez un terminal dans le dossier racine du dépôt et courir:

    $ python3 -m build --wheel

    Ensuite, recherchez le sous-dossier dist contenant un .whl dossier. Par example:

    MyModule-0.0.1-cp39-cp39-linux_x86_64

    Le nom du fichier contient beaucoup d’informations. Après le nom et la version du module, il spécifie l’interpréteur Python (CPython 3.9) et l’architecture cible (x86_64).

    À ce stade, vous pouvez installer et tester la roue nouvellement créée :

    $ python3 -m venv venv_test_wheel/
    
    $ source venv_test_wheel/bin/activate
    
    $ python3 -m pip install dist/MyModule-0.0.1-cp39-cp39-linux_x86_64.whl

    (Stephan Avenwedde, CC BY-SA 4.0)

    Vous avez maintenant une roue, que vous pouvez transmettre à quelqu’un utilisant le même interpréteur sur la même architecture. C’est le strict minimum, je vais donc aller plus loin et vous montrer comment créer des roues pour d’autres plates-formes.

    Construire la configuration

    En tant que mainteneur de paquet, vous devez fournir une roue appropriée pour autant de plates-formes que possible. Heureusement, il existe des outils pour vous faciliter la tâche.

    Maintien de la compatibilité Linux

    Lors de la construction d’extensions Python C/C++, les binaires résultants sont liés aux bibliothèques standard du système de construction. Cela pourrait entraîner des incompatibilités sous Linux, avec ses différentes versions de glibc. Un module d’extension Python C/C++ construit sur un système Linux peut ne pas fonctionner sur un autre système Linux comparable en raison, par exemple, de l’absence d’une certaine bibliothèque partagée. Pour éviter de tels scénarios, PEP 513 a proposé une balise pour les roues qui fonctionnent sur de nombreuses plates-formes Linux : beaucoup de Linux.

    La construction pour la plate-forme manylinux provoque une liaison avec un noyau défini et une ABI de l’espace utilisateur. Les modules conformes à cette norme devraient fonctionner sur de nombreux systèmes Linux. Les beaucoup de Linux tag développé au fil du temps, et dans sa dernière norme (PPE 600), il nomme directement le glibc versions auxquelles le module était lié (manylinux_2_17_x86_64par exemple).

    En plus de beaucoup de Linuxil y a la plateforme musllinux (PEP 656), qui définit une configuration de construction pour les distributions utilisant musulman libc comme Alpin Linux.

    Roue de construction CI

    Les cibuildwheel Le projet fournit des configurations de construction CI pour de nombreuses plates-formes et les systèmes CI/CD les plus largement utilisés.

    De nombreuses plates-formes d’hébergement Git intègrent des fonctionnalités CI/CD. Le projet est hébergé sur GitHub, vous pouvez donc utiliser GitHub Actions en tant que serveur CI. Suivez simplement le instructions pour les actions GitHub et fournissez un fichier de workflow dans votre référentiel : .github/workflows/build_wheels.yml.

    (Stephan Avenwedde, CC BY-SA 4.0)

    Un push vers GitHub déclenche le workflow. Une fois le workflow terminé (notez qu’il a fallu plus de 15 minutes), vous pouvez télécharger une archive contenant une roue pour différentes plates-formes :

    (Stephan Avenwedde, CC BY-SA 4.0)

    Vous devez toujours empaqueter ces roues manuellement si vous souhaitez les publier sur PyPi. En utilisant CI/CD, il est possible d’automatiser le processus de livraison à PyPi. Vous trouverez d’autres instructions dans documentation cibuildwheels.

    Emballer

    Les différents formats peuvent faire du packaging des modules Python un processus obtus pour les débutants. La connaissance des différents formats de paquets, de leur objectif et des outils impliqués dans le processus de conditionnement est nécessaire pour les mainteneurs de paquets. J’espère que cet article éclairera le monde de l’emballage Python. En fin de compte, en utilisant un système de construction CI/CD, fournir des packages au format de roue avantageux devient un jeu d’enfant.

    Source

    Houssen Moshinaly

    Pour contacter personnellement le taulier :

    Laisser un commentaire

    Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

    Copy code