Mathieu Agopian : Le miroir PyPI du pauvre

Deux notes pour commencer cet article :

Bonjour ami lecteur. Je vais te conter mon histoire, en me disant que tu es peut-être toi aussi passé par là, et que cette expérience t'enrichira.

Tout d'abord, le personnage principal : moi. Je suis fainéant (revoir la présentation [5] que j'ai donnée à Djangocong 2010 [6] à ce sujet).

Les protagonistes

pip [7] et PyPI [8]. Si tu ne connais pas pip, l'outil à utiliser pour installer des paquets python, honte à toi, arrête de lire immédiatement et documente toi à ce sujet.

Oui, maintenant.

PyPI (le Python Package Index) est le site listant et hébergeant la plupart des paquets, applications et librairies python qui ne sont pas dans la libraire standard.

L'intrigue

Je travaille sur un projet Django [9], et ayant fait les choses proprement, j'ai un ficher requirements.pip listant les noms ou les urls des différents paquets que j'utilise.

Ce fichier est utilisé par pip pour installer automatiquement toutes les dépendances de mon projet, par exemple lors de l'installation d'un nouveau serveur ou du déploiement de mon projet :

pip install -r requirements.pip

Les péripéties

Elles te sont peut-être arrivées à toi aussi :

Une solution à tous ces problèmes est d'utiliser un miroir local de PyPI, qui contiendra tous les paquets nécessaires à notre projet, dans leur version utilisée.

Il y a plusieurs projets qui permettent de faire ça de manière plus ou moins automatique :

Mais ça nécessite d'installer et de gérer une application de plus, or, comme je l'ai précisé, je suis fainéant, et je n'ai pas envie de consacrer une machine (et une installation de serveur web) pour ça.

Le sauveur

pip à la rescousse, avec deux options très pratiques :

--find-links
URL ou chercher des paquets (notre miroir local !)
--no-index
ignorer les index de paquets (comme PyPI), et ne regarder que sur l'URL fournie à --find-links

Mais il y a mieux. Il est possible de mettre l'option --find-links en tout début du fichier requirements.pip pour ne pas avoir besoin de l'utiliser en ligne de commande (et donc ne pas changer nos habitudes, parfait pour un fainéant ;).

Pour la deuxième option, elle n'est pas reconnue dans le fichier, mais on peut utiliser l'option --index-url à la place. On est alors sûr que pip n'essaiera pas de trouver un meilleur paquet (meilleure note, version plus récente) sur PyPI.

Maintenant qu'on sait comment utiliser notre miroir local, il ne reste plus qu'à le créer :

  1. Générer la liste exhaustive de tous les paquets et dépendances
  2. Les faire télécharger par pip dans un répertoire
  3. Servir ce répertoire avec un serveur web
  4. Modifier le fichier requirements.pip

Générer la liste des paquets

Rien de plus simple :

pip freeze > freezed.pip

Télécharger les paquets

On le fait faire par pip, ce serait trop long et fastidieux de tout télécharger (les paquets et leurs dépendances) sur PyPI (ou git, svn, mercurial, …) manuellement :

mkdir pypi
pip install -r freezed.pip --upgrade --download=pypi --build=pypi

Servir le répertoire avec un serveur web

SimpleHTTPServer [17] à la rescousse :

cd pypi
python -m SimpleHTTPServer

Le miroir est maintenant accessible sur http://localhost:8000.

Il existe sinon une autre méthode qui consiste à fournir directement une URL de type file:///path/to/mirror/folder au paramètre find-links. Dans ce cas, pas besoin de serveur web !

Modifier le fichier requirements.pip

La dernière étape de notre périple, avant de rentrer voir sa princesse, de vivre heureux et d'avoir beaucoup beaucoup d'enfants.

Comme nous l'avons vu, il faut placer les deux lignes suivantes en tête du fichier requirements.pip :

--find-links http://localhost:8000
--index-url http://localhost:8000

Ayant maintenant notre propre miroir local, il ne faut plus utiliser les URLs de téléchargement sur git/svn/mercurial/… pour les paquets qu'on ne souhaite pas réinstaller à chaque fois :

  • les paquets devant être réinstallés à partir de leur dépôts VCS à chaque fois resteront avec leur URL complète
  • les autres paquets installés à l'origine à partir de dépôts n'ont plus besoin de leur url : ne conserver que leur nom (la partie après #egg= dans leur URL)
  • tous les autres peuvent être listés sans leurs dépendances

Par exemple, si vous avez installé django-notification de la sorte :

pip install -e git+ssh://git@github.com/jtauber/django-notification.git#egg=django_notification:nohlsearch

Il suffira de mettre la ligne suivante dans le fichier requirements.pip :

django-notification

À partir de maintenant, tout appel à la commande suivante ira automatiquement installer les paquets disponibles dans le répertoire du miroir local (si le SimpleHTTPServer est lancé bien entendu) :

pip install -Ur requirements.pip

Tous les articles

  1. Vim, Restructured Text et espaces insécables
  2. VIM et la correction orthographique
  3. Djangocong 2012 !
  4. Point-virgule
  5. La bidouille django du jour: appeller un templatetag depuis un autre templatetag
  6. Contribuer à Django, premiers pas (patcher la doc)
  7. Sud Web, c'est bon pour ton web
  8. Contribuer à Django, premiers pas (les outils, l'environnement)
  9. Contribuer à Django, premiers pas (revue de tickets)
  10. Djangocong 2011 : une cuvée d'exception
  11. django et le handler500: retourner une erreur 503
  12. La technique pomodoro : retour après plus d'un mois d'utilisation
  13. La technique pomodoro : retour après deux semaines d'utilisation
  14. django: redimensionner une image à la volée en préservant son ratio
  15. Django forms, HTML5 et fieldsets
  16. Double encodage utf8 : afficher correctement avec python et django
  17. La vie a la couleur qu'on veut bien lui donner
  18. lancer gunicorn avec supervisord
  19. PyCon.fr 2010 : retour sur une conférence organisée par l'AFPY
  20. djangocong : rencontre Django à Marseille
  21. MySQL, mysqldump et PHP : convertir de latin1 vers utf8
  22. Django : Envoyer des emails HTML avec images inline (intégrées)
  23. lancer gunicorn avec runit
  24. gunicorn: un server wsgi ultra simple à utiliser et configurer
  25. Installer PIL (Python Imaging Library) facilement avec pip
  26. Obfuscation de l'email alternative et accessible
  27. Linux: savoir si le processeur est 32bits ou 64bits
  28. PyCON.fr, excellent!
  29. PyCon.fr: venez m'y voir!
  30. Le contrôle de versions de sources: pourquoi?
  31. Django, sqlite et mod_wsgi, attention au piège!
  32. Checklist: différences entre MySQL et les modèles Django
  33. MySQL et les modèles Django
  34. Apprendre à faire, et faire
  35. Django FileField et ImageField, upload_to et shell python
  36. Django svn et mod_wsgi, attention au piège!
  37. 30 ans, et toutes mes dents