Makina Blog

Le blog Makina-corpus

Gérer ses dépendances de paquets Python


Contexte : je viens de découvrir Python et je me suis trouvé un peu perdu dans cette jungle de pip, easy_install, setuptools et autre virtualenv. Maintenant que j'en suis sorti, j'ai envie d'aider mon prochain.

Un peu d'histoire

Avant, il y avait python 2, mais ça c'était avant, car à moins d'avoir de très bonnes raisons, il est recommandé d'utiliser python 3 pour tous vos nouveaux projets. C'est donc ce que j'ai fait. Le problème, c'est que les tutoriaux et les articles du web parlent encore d'anciennes méthodes. Faisons un tour des notions :

  • setuptools : cet outil, intégré à python à travers la bibliothèque standard python distutils sert à packager des projets python.
    • Elle permet de créer des eggs (car les serpents font des œufs). Les eggs sont un moyen d'ajouter des informations additionnelles aux paquets python, notamment les dépendances.
    • Elle permet également de créer des wheel (car on a réinventé la roue), là où les eggs fournissent du code source ensuite compilé, les wheel fournissent des fichiers déjà compilés pour la plateforme.
  • easy_install : cet outil est un module de setuptools et permet d'interroger PyPI (Python Package Index) pour télécharger un paquet et ses dépendances. Malheureusemenent, il est limité et ne permet pas de lister les paquets existants ni de le mettre à jour, il a donc été progressivement abandonné.
  • pip : cet outil, maintenant inclus dans les dernières installations de Python, permet de télécharger et gérer les paquets python pour un projet. Son nom est un acronyme récursif pour Pip installs packages ou Pip installs python. Il est souvent utilisé en conjonction avec virtualenv pour éviter d'installer des paquets globalement dans le système.
  • buildout : cet outil d'automatisation fait plus de choses que le couple pip + virtualenv, il permet non seulement de télécharger et installer des paquets python (lui aussi en dehors du scope global), mais il peut également effectuer d'autres actions comme générer un fichier de configuration apache, installer une tâche cron, ou redémarrer des services.

Nous nous intéresserons au cas de pip, car buildout est plus complexe mais répond aux mêmes problèmatiques qu'un trio fabric + virtualenv + pip. À vous donc de décider si vous préférez séparer les logiques, ou bien tout regrouper au sein d'un même fichier de configuration. Si vous voulez suivre cette voie, vous pouvez consulter cet article pour passer de pip+virtualenv à buildout.

Introduction à pip

Pip étant le standard que l'on apprend dans les tutoriaux, voyons ses quelques commandes de base :

pip install

Installe un paquet, par défaut, si l'on ne donne que le nom du paquet, pip ira le chercher dans PyPI et prendra sa dernière version. Un paquet peut avoir une version, qui répond à une ou des conditions. Par défaut, pip installera des wheels s'il les trouve, sinon il prendra la source, vous pouvez forcer ceci avec l'option --no-binary.

Pip supporte également le fait d'installer des paquets depuis des gestionnaires de version (Git, SVN, mercurial, Bazaar, etc.), ce qui permet de référencer des forks de projet lorsque ceux-ci ont un bug qu'il nous faut résoudre rapidement. Par exemple, on installera depuis github de cette manière git://github.com/MyProject.git@master#egg=MyProject, la partie #egg=MyProject permet de renseigner le nom système du paquet afin que pip s'en serve dans sa résolution de dépendances.

Pour installer un paquet avec pour but de l'éditer (par exemple un fork), il faut renseigner l'option -e comme par exemple pip install -e git+https://github.com/django/django.git#egg=Django, ceci installera Django dans le dossier ./src de votre virtualenv.

Niveau sécurité, il est possible de vérifier le(s) hash(s) des paquets récupérés en ajoutant l'option --hash.

Lorsqu'on veut installer plusieurs paquets d'un seul coup (comme par exemple lorsqu'on démarre ou déploie un projet), il est possible de renseigner une liste de paquets avec toutes les options ci-dessus dans un fichier requirements.txt par exemple. On installera alors toute la liste en lançant pip install -r requirements.txt.

Voici un exemple :

# Django & co
Django==1.8.7
django-autocomplete-light==2.2.10
django-autoslug==1.9.3
django-braces==1.8.1
django-compat==1.0.8
django-crispy-forms==1.5.2
django-debug-toolbar==1.4
django-envelope==1.1
django-filter==0.11.0
django-form-utils==1.0.3
django-formtools==1.0
django-hijack==2.0.0
django-localflavor==1.2
django-sessioninfo==0.0.3
django-template-debug==0.3.5
django-versatileimagefield==1.1
docutils==0.12
lxml==3.5.0
Pillow==3.0.0
psycopg2==2.6.1
six==1.10.0
sqlparse==0.1.18

# Generating PDFs
pycparser==2.14
Pyphen==0.9.2
PyYAML==3.11
tinycss==0.3
WeasyPrint==0.24
html5lib==0.9999999
cairocffi==0.7.2
CairoSVG==1.0.19
cffi==1.3.1
cssselect==0.9.1

pip uninstall

Désinstalle un paquet, cette commande laissera votre système de fichiers propre après le test d'un paquet. Il enlevera également les métadonnées concernant l'egg.

pip list

Liste les paquets installés dans votre virtualenv, assez pratique pour avoir une vue d'ensemble de votre projet, pour voir quelles versions sont installées, et voir s'il n'y a pas des paquets qui seraient non utilisés.

Une option --outdated permet de voir quels paquets peuvent être mis à jour.

pip show

Permet d'avoir des informations à propos d'un paquet : son emplacement, sa version, ses dépendances.

pip search

Permet de faire une recherche dans PyPI, et affichera la description de chacun des paquets dans les résultats.

pip freeze

Là où pip install peut prendre en paramètres un fichier requirements.txt, pip freeze peut générer celui-ci. Un petit conseil si vous commentez vos fichiers de requirements, utilisez l'option -r pour que pip reprenne les commentaires et l'ordre des paquets.

Maintenir ses paquets avec pip

Avec tout ce qui est inclus dans pip, on croirait être fin prêts pour gérer les paquets au fur et à mesure de notre projet, sauf que non, comment mettre à jour ces paquets facilement, pip install --upgrade pour chacun des paquets, fastidieux, non ?

pip review

Cette commande s'installe avec pip install pip-review et par défaut vérifie les nouvelles versions de vos paquets, pip-review --auto les installera automatiquement, et pip-review --interactive vous demandera confirmation pour chacun des paquets à mettre à jour.

Il reste encore un problème avec cette technique : on sépare souvent les paquets par plateforme, requirements-dev.txt pour les paquets nécessaire au développement (par ex.: ipdb, selenium, coverage, …) et requirements.txt pour les paquets nécessaires au projet. Sauf que même avec l'option -r, pip freeze ne permet pas de séparer les paquets en deux selon la plateforme.

pip compile

Entre pip-tools (pip install pip-tools), celui-ci requiert un fichier requirements.in, où seuls les paquets feuilles (c-à-d sans les dépendances) sont listés, sans les versions, cela permet de simplifier qui a besoin de quoi, car on ne sait pas toujours qui a besoin de quoi.

# Django-related
django-autocomplete-light
django-autoslug
django-braces
django-crispy-forms
django-debug-toolbar
django-envelope
django-filter
django-form-utils
django-formtools
django-hijack
django-localflavor
django-template-debug
django-versatileimagefield
psycopg2
PyYAML
docutils

# PDFs
WeasyPrint

Il est également possible de créer un fichier dev-requirements.in

-r requirements.in

# Tests
coverage
selenium

# Debug
ipdb

# Package management
pip-autoremove
pip-review
pip-tools

La commande pip-compile suivi du nom du fichier *.in générera le contenu de *requirements.txt correspondant, avec en commentaire le(s) paquet(s) parent(s) sur les dépendances, et les versions fixées. Il est ensuite conseillé de tracker les fichiers .in et .txt.

#
# This file is autogenerated by pip-compile
# Make changes in requirements.in, then run this to update:
#
#    pip-compile requirements.in
#
cairocffi==0.7.2          # via cairosvg, weasyprint
cairosvg==1.0.19          # via weasyprint
cffi==1.4.2               # via cairocffi, weasyprint
cssselect==0.9.1          # via weasyprint
django-autocomplete-light==2.2.10
django-autoslug==1.9.3
django-braces==1.8.1
django-compat==1.0.8      # via django-hijack, django-sessioninfo
django-crispy-forms==1.5.2
django-debug-toolbar==1.4
django-envelope==1.1
django-filter==0.11.0
django-form-utils==1.0.3
django-formtools==1.0
django-hijack==2.0.0
django-localflavor==1.2
django-sessioninfo==0.0.3  # via django-hijack
django-template-debug==0.3.5
django-versatileimagefield==1.2.1
django==1.9
docutils==0.12
html5lib==0.9999999       # via weasyprint
lxml==3.5.0               # via weasyprint
pillow==3.0.0             # via django-versatileimagefield
psycopg2==2.6.1
pycparser==2.14           # via cffi
pyphen==0.9.2             # via weasyprint
pyyaml==3.11
six==1.10.0               # via django-autocomplete-light, django-braces, django-compat, html5lib
sqlparse==0.1.18          # via django-debug-toolbar
tinycss==0.3              # via weasyprint
weasyprint==0.25

pip sync

Cette commande prend en paramètre un fichier .txt et s'occupe de désinstaller les anciennes versions et d'installer les nouvelles versions.

Astuce

Pour passer d'un fichier requirements.txt à un requirements.in facilement, je vous conseille pip-autoremove (pip install pip-autoremove) qui permet de vérifier que des paquets ne sont pas orphelins, et son option --leaves ne liste que les feuilles à mettre dans votre requirements.in : pip-autoremove --leaves | cut -f 1 -d ' ' | sort > requirements.in

Actualités en lien

Image
Encart PyConFr 2024
21/10/2024

Makina Corpus est spon­sor de la PyConFR 2024

Le soutien de Makina Corpus à la PyConFR 2024, qui se tient du 31 octobre au 3 novembre 2024 à Stras­bourg, reflète ses valeurs de partage et d’in­no­va­tion, et son enga­­ge­­ment envers la commu­nauté dyna­­mique et ouverte de Python.

Voir l'article
Image
Webinaire découverte de Canari
10/04/2024

Revoir les webi­naires : décou­verte de l’ou­til CANARI-France

L’ap­pli­ca­tion CANARI-France est destiné aux acteurs agri­coles afin de calcu­ler des indi­ca­teurs agro-clima­tiques à partir de projec­tions clima­tiques. Décou­vrer en le replay des 4 webi­naires orga­ni­sés par Sola­gro et l’ADEME.

Voir l'article
Image
Python
26/07/2023

La formation Python éligible au CPF est enfin arrivée

Makina Corpus propose un nouvelle formation Python éligible au CPF. Grâce à cette certification, cette formation peut être entièrement financée par votre compte Compte Personnel de Formation.

Voir l'article

Inscription à la newsletter

Nous vous avons convaincus