Je présente dans cet article mon workflow concernant l'utilisation de virtualenv et pip ...
Je tiens à préciser qu'il y a d'autres workflows possibles, par exemple l'utilisation de buildout mais ce n'est pas le sujet de cet article.
Méthode « classique »
Voici la méthode que je nomme "classique" car je pense qu'elle est beaucoup utilisée. J'utilisais cette méthode il y a encore quelques mois.
Prérequis sur la machine (je ne précise pas leur installation, ce n'est pas mon sujet) :
- python
- distribute /setuptools
- pip
- virtualenv
Je prépare un dossier de travail et je clone mon projet :
$ mkdir ~/my_project/ $ cd ~/my_project/ $ git clone http://stephane@repos.stephane-klein.info/example1 . $ ls -1 devel-requirements.txt example1 requirements.txt setup.py tests unittest.cfg
Je crée un environnement virtuel python dans le dossier courant :
$ virtualenv .
Comme mon projet est un package python, mon dossier contient un fichier setup.py
.
Je lance son installation mais avec l'option -e
pour qu'il soit éditable.
$ bin/pip install -e .
Je peux maintenant utiliser mon package :
$ bin/python >>> import example1 >>> example1.hello_world() Hello world
Voila, mon installation en mode développement est finie... La seule difficulté pour certaines personnes c'est l'installation des dépendances de bases (distribute/setuptools, pip, virtualenv).
La suite de l'article présente une solution plus simple, avec moins de dépendances.
Installation en mode « édition » ?
Voici deux méthodes pour installer un package python à partir du fichier setup.py
:
$ python setup.py install
ou
$ pip install .
Ces deux commandes installent le package dans le dossier site-packages
de votre environnement python.
Si vous modifiez le code source de votre package, vos modifications ne seront pas "visibles" lors de l'exécution du package dans votre environnement, car une copie des fichiers sources a été faite lors de l'installation.
Par conséquent, à chaque modification, vous allez devoir installer de nouveau votre package.
Ceci est très pénible si vous êtes en train de développer votre application.
C'est là que l'installation en mode "editable" entre en jeu.
Lors de l'installation en mode édition, le code source n'est pas copié vers le dossier site-packages
mais un lien symbolique est utilisé.
Vos modifications seront tout le temps pris en compte, sans passer par l'étape d'installation.
Voici deux commandes pour effectuer une installation en mode « édition » :
$ python setup.py develop
ou
$ pip install -e .
Par le passé, python setup.py develop
ne permettait pas la désinstallation du package. Maintenant ce n'est plus le cas, par conséquent ces deux commandes semblent être synonymes.
Utilisation des fichiers requirements.txt
L'option --requirement
de pip est intéressante, elle permet d'installer des dépendances depuis un fichier texte.
Bon, je pense que je n'apprends rien à personne, cette option est très connue.
Par contre, sa syntaxe est moins bien connue, exemples :
-
-e package
permet d'installer un package en mode édition -
-e .
est équivalent àpip install -e .
oupython setup.py develop
-
-e https://github.com/pypa/pip.git#egg=pip
fait un clone du dépôt danssrc/pip/
et installe le package en mode édition -
-r requirements.txt
il est possible d'installer un autre fichier de "requirements"
Il est souvent utile d'avoir des dépendances de packages pour la version de production et des dépendances supplémentaires pour le mode développement.
Par conséquent on trouve souvent deux fichiers requirements :
-
requirements.txt
-
devel-requirements.txt
Exemple de fichier devel-requirements.txt
que j'utilise :
-e . git+https://github.com/nose-devs/nose2.git#egg=nose2 sphinx Sphinx-PyPI-upload
Explications :
- j'utilise
-e .
pour installer le package sur lequel je suis en train de travailler - j'installe une version qui n'est pas encore releasé de nose2
- j'installe des outils de documentation dont j'ai besoin en mode développement
Donc pour installer la version de développement de mon projet, je fais :
$ pip install -r devel-requirements.txt
Installation de requirements.txt depuis setup.py
Il est possible d'avoir un setup.py
qui utilise la liste des dépendances de requirements.txt
.
Exemple :
from setuptools import setup, find_packages def parse_requirements(file_name): requirements = [] for line in open(file_name, 'r').read().split('\n'): if re.match(r'(\s*#)|(\s*$)', line): continue if re.match(r'\s*-e\s+', line): requirements.append(re.sub(r'\s*-e\s+.*#egg=(.*)$', r'\1', line)) elif re.match(r'\s*-f\s+', line): pass else: requirements.append(line) return requirements setup( name='my_project', version='0.1.0', packages=find_packages(), include_package_data=True, zip_safe=False, install_requires=parse_requirements("requirements.txt") )
Ici, parse_requirements
lit le fichier requirements.txt
et utilise sont contenu avec l'argument install_requires
de la fonction setup
.
Mais attention ! La fonction setup
ne sait pas traiter la syntax spécifique à pip. Par exemple, les lignes du style git+http...
ne fonctionneront pas.
Méthode avec bootstrap de virtualenv
Depuis quelques mois, j'utilise la fonctionnalité « Creating Your Own Bootstrap Scripts » de virtualenv.
Cette fonctionnalité permet de générer un fichier python, qui installera automatiquement un environnement virtuel comme la commande virtualenv .
mais sans aucune dépendance à installer.
pip
sera bien présent dans bin
même si vous ne l'avez pas installé avant.
Utilisation de bootstrap.py
Avant de voir comment générer un fichier bootstrap.py
, nous allons voir comment l'utiliser :
$ mkdir ~/my_project/ $ cd ~/my_project/ $ git clone http://stephane@repos.stephane-klein.info/example1.1 . $ python bootstrap.py $ bin/pip install -r devel-requirements.txt
Voila, rien de plus... on va voir par la suite qu'il est même possible d'installer automatiquement les devel-requirements.txt
.
Génération d'un bootstrap.py
La documentation de virtualenv, donne une exemple de génération d'un fichier bootstrap.py
.
Personnellement, je place un fichier nommé create-bootstrap.py
dans le dossier où je souhaite créer mon fichier bootstrap.py
. Ce fichier create-bootstrap.py
contient le code suivant :
import virtualenv, textwrap output = virtualenv.create_bootstrap_script(textwrap.dedent(""" import os, subprocess def adjust_options(options, args): if len(args) == 0: args.append('.') def after_install(options, home_dir): subprocess.call([ os.path.join('bin', 'pip'), 'install', '-r', 'devel-requirements.txt' ]) """)) f = open('bootstrap.py', 'w').write(output)
La ligne args.append('.')
indique qu'au lancement de bootstrap.py
l'environnement python sera installé dans le dossier courant.
Un peu plus bas, je lance l'installation de devel-requirements.txt
.
J'ai juste à lancer (une fois) python create-bootstrap.py
pour générer bootstrap.py
:
$ ls -1 create-bootstrap.py setup.py devel-requirements.txt requirements.txt $ python create-bootstrap.py $ ls -1 bootstrap.py create-bootstrap.py devel-requirements.txt requirements.txt setup.py
Maintenant, j'ajoute create-bootstrap.py
et bootstrap.py
dans mon dépôt.
$ git add create-bootstrap.py bootstrap.py
Par la suite, il n'y a plus besoin d'utiliser create-bootstrap.py
à moins de vouloir modifier bootstrap.py
pour ajouter/supprimer des actions automatiques.
Pour finir, mon workflow complet
Prérequis:
- python
Simple niveau prérequis, non ? Un peu comme buildout pour ceux qui connaissent.
Je prépare un dossier avec mon projet :
$ mkdir ~/my_project/ $ cd ~/my_project/ $ git clone http://my-project.org/ .
En une seule commande, j'installe mon environnement python et mon projet en mode développement (éditable).
$ python bootstrap.py