Makina Blog
Python : Bien configurer son environnement de développement
Comment utiliser les bonnes pratiques de développement Python.
C'est quand même plus sympa de développer quand notre environnement de développement est bien configuré ! Ce didacticiel est une introduction à quelques bonnes pratiques qui vous permettront d'avoir un environnement de développement Python aux petits oignons :
- Travailler avec des environnements virtuels et les associer aux projets,
- Personnaliser le script de démarrage du shell Python,
- Valider son code Python,
- Standardiser l'exécution des tests.
Pré-requis
Je considère dans ce tutorial que vous avez déjà installé Python > 2.7.9 et > 3.4.
Ces versions de Python fournissent par défaut pip qui est un outil permettant de télécharger et d'installer des modules Python depuis le Python Package Index (PyPI).
1 - Principe de base : Travailler avec des environnements virtuels Python
Les environnements virtuels Python permettent d'avoir des installations de Python isolées du système et séparées les unes des autres. Cela permet de gérer plusieurs projets sur sa machine de développements, certains utilisant des modules de versions différentes, voir même des versions différentes de Python.
Installation de Virtualenv
pip install virtualenv
Exemple d'utilisation
mkdir -p ~/virtualenvs
virtualenv ~/virtualenvs/project1
Virtualenv créait ainsi un environnement Python complètement isolé, dans lequel on va pouvoir installer, mettre à jour, supprimer des modules Python après avoir activé l'environnement :
# Activation de l'environnement
source ~/virtualenvs/project1/bin/activate
# Le path de notre interpréteur Python
(project1) which python
~/virtualenvs/project1/bin/python
# Installer un module, le mettre à jour
(project1) pip install gunicorn
(project1) pip install gunicorn --upgrade
(project1) pip install requests
# Installer une version spécifique d'un module
# ou downgrader vers une version antérieure
(project1) pip install Django==1.8.6
(project1) pip install Django==1.8.5
# Supprimer un module
(project1) pip uninstall requests
# Lister le contenu de notre environnement
(project1) pip freeze
Django==1.8.5
gunicorn==19.4.1
# En enregistrer le contenu
(project1) pip freeze > requirements.txt
# Et pour installer l'ensemble en une commande sur une autre machine
(project1) pip install -r requirements.txt
Tip : Pensez à mettre à jour pip lui-même de temps en temps :
(project1) pip install --upgrade pip
Et pour sortir de l'environnement :
(project1) deactivate
À la création de l'environnement virtuel, vous pouvez choisir si ce dernier hérite ou non des modules du Python système. Par défaut, les modules du Python système ne sont pas hérités. Pour forcer l'héritage :
virtualenv --system-site-packages ~/virtualenvs/project2
Si vous souhaitez utiliser une version spécifique de Python, ou avoir pour un même projet un environnement Python 2 et un autre en Python 3 :
virtualenv ~/virtualenvs/project3-py2 -p /usr/bin/python2.7
virtualenv ~/virtualenvs/project3-py3 -p /usr/bin/python3.4
2 - J'ai 99 environnements virtuels, comment me faciliter la vie ?
virtualenvwrapper est la solution, il va nous nous offrir :
- Une centralisation des environnements virtuels et des projets associés,
- Une gestion simple des environnements virtuels (création, suppression, copie),
- Une commande pour passer facilement d'un environnement à l'autre,
- De l'autocomplétion sur les noms des environnements virtuels,
- Pour les utilisateurs avancés la possibilité de configurer des hooks par environnement.
Installons et configurons virtualenvwrapper
# Installation
pip install virtualenvwrapper
# Config à ajouter dans ~/.bashrc ou ~/.profile
# - dossier contenant les environnements virtuels
export WORKON_HOME=~/.virtualenvs
mkdir -p $WORKON_HOME
# - dossier contenant les projets associés
export PROJECT_HOME=~/pyprojects
mkdir -p $PROJECT_HOME
# - s'assurer que virtualenvwrapper est toujours disponible
source /usr/local/bin/virtualenvwrapper.sh
Pensez à relancer le terminal pour activer les modifications et permettre à virtualenvwrapper de s'installer (les messages d'installation ne s'afficheront plus par la suite).
Gestion des environnements
# Création d'un premier environnement
mkvirtualenv project1
# L'environnement est créé et automatiquement activé
# Installons Django :
(project1) pip install Django==1.8
# Créons un deuxième environnement
(project1) mkvirtualenv project2
(project2) pip install Django==1.7
(project2) cdvirtualenv
(project2) pwd
~/.virtualenvs/project2
(project2) cdsitepackages
(project2) pwd
~/.virtualenvs/project2/lib/python2.7/site-packages
# Lister les environnements
(project2) lsvirtualenv -b
project1
project2
# Passer d'un environnement à l'autre
(project2) workon project1
(project1) workon project2
(project2)
# Supprimer un environnement
(project2) deactivate
rmvirtualenv project2
Gestion des projets associés aux environnements
# Créer un projet vide et son environnement virtuel associé
mkproject project3
(project3) cdvirtualenv
(project3) pwd
~/.virtualenvs/project3
(project3) cdproject
(project3) pwd
~/pyprojects/project3
Ok, mais comment faire si on a déjà un projet existant depuis longtemps et que l'on ne souhaite pas le redéployer ou en modifier les chemins d'installation ? La commande setvirtualenvproject arrive à la rescousse en permettant d'associer un environnement virtuel existant à un projet existant :
setvirtualenvproject virtualenv_path project_path
# Une fois l'environnement virtuel activé,
# les commandes cdvirtualenv et cdproject sont opérationnelles.
Attention, si l'environnement virtuel n'est pas situé dans le dossier $WORKON_HOME (où les environnements sont créés par les commandes mkvirtualenv et mkproject), il ne sera pas utilisable avec la commande workon. Pour y remédier, il suffit d'y créer un lien symbolique :
cd $WORKON_HOME
ln -s virtualenv_path
Aller plus loin avec virtualenvwrapper
3 - Personnaliser le script de démarrage du shell Python
Python met à disposition la variable d'environnement PYTHONSTARTUP qui permet de choisir un script de démarrage qui sera exécuté automatiquement lorsque l'on démarre un shell Python. Cette variable attend un chemin absolu vers un fichier qui peut contenir n'importe quel code Python :
# Config à ajouter dans ~/.bashrc ou ~/.profile
export PYTHONSTARTUP=~/python_startup_script.py
Voici un exemple de script de démarrage qui :
- Importe quelques fonctions de compatibilité Python 3
- Importe des modules de la librairie standard que j'utilise fréquemment
- Importe des modules additionnels potentiellement présents
- Et si on est au sein d'un environnement virtuel :
- Affiche le nom de l'environnement virtuel dans le prompt
- Affiche la liste des modules qui ont été installés avec pip
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Compatibilité Python 3
from __future__ import unicode_literals, print_function, absolute_import
# Quelques modules de la lib standard
import sys
import os
import json
import re
import subprocess
from pprint import pprint
from datetime import datetime, timedelta
# Modules additionnels potentiellement présents
try:
import requests
except ImportError:
pass
# Environnement virtuel ?
env = os.environ.get('VIRTUAL_ENV')
if env:
# Affiche le nom de l'environnement virtuel dans le prompt
env_name = os.path.basename(env)
sys.ps1 = '({0}) {1} '.format(env_name, getattr(sys, 'ps1', '>>>'))
# Affiche la liste des modules qui ont été installés avec pip
print("\nVirtualenv '{}' contains:".format(env_name))
cmd = subprocess.check_output(
[env + "/bin/pip", "freeze"],
stderr=subprocess.STDOUT
)
try:
cmd = cmd.decode('utf8')
except:
pass
modules = [
"'{}'".format(m.split('==')[0]) # exemple: u'Django==1.8.4' => u'Django'
for m in cmd.strip().split("\n")
]
print(', '.join(sorted(modules)) + '\n')
print('Use Python startup script : {}\n'.format(os.environ.get('PYTHONSTARTUP')))
Et à présent lorsque l'on lance un shell au sein d'un environnement virtuel :
mkvirtualenv project4
(project4) pip install requests Django
(project4) python
[...]
Virtualenv 'project4' contains:
'Django', 'requests'
Use Python startup script : ~/python_startup_script.py
(project4) >>> pprint({i: 'c' + 'o'*i + 'l' for i in range(2, 10)})
{2: u'cool',
3: u'coool',
4: u'cooool',
5: u'coooool',
6: u'cooooool',
7: u'coooooool',
8: u'cooooooool',
9: u'coooooooool'}
4 - Valider son code Python avec flake8
flake8 permet de valider son code Python au regard des conventions de codage PEP 8 (Style guide for Python Code) et de pyflakes (détection d'erreurs).
Une fois installé, flake8 peut être invoqué sur un module Python ou un dossier complet, exemple :
# Créons un projet dédié
mkproject test-flake8
(test-flake8) cdproject
# Installation de flake8
(test-flake8) pip install flake8
Créons un petit module Python (mytest.py) comportant quelques erreurs :
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import mylib # noqa (i.e ignore cette erreur)
def foo( bar):
print 'foo {}'.format(bar)
et invoquons flake8 :
(test-flake8) flake8 mytest.py
mytest.py:4:1: F401 'os' imported but unused
mytest.py:7:1: E302 expected 2 blank lines, found 1
mytest.py:7:9: E201 whitespace after '('
mytest.py:8:31: W292 no newline at end of file
Ceci dit, tous les éditeurs de code Python dignes de ce nom intègrent ou permettent d'intégrer via un plugin le support de flake8… donc aucune excuse pour ne pas produire du beau code Python !
Jetez également un coup d'oeil à isort qui permet de trier dans l'ordre alphabétique les imports d'un module Python et de les organiser par section (les imports Future, puis ceux de la librairie standard, …).
5 - Standardiser l'exécution des tests avec tox
tox permet d'automatiser l'exécution de la suite de tests d'un projet dans plusieurs environnements virtuels (différentes versions de Python ou d'interpréteurs) en une seule commande. Cela s'avère vite indispensable lorsque l'on développe un module open source.
Intégrons le à un projet existant, au hasard Django :
# Créons un projet dédié
mkproject tox-django
(tox-django) cdproject
# Installation de tox
(tox-django) pip install tox
# Clone du code du projet Django
(tox-django) git clone git@github.com:django/django.git
Ajoutons à présent un fichier tox.ini permettant d'installer le projet et de lancer la suite de tests du projet dans deux environnements : Python 2.7 et Python 3.4. On en profite pour générer un rapport de couverture de test HTML qui s'ouvrira automatiquement.
(tox-django) cd django
(tox-django) vi tox.ini
# tox.ini, à mettre dans le dossier que setup.py
[tox]
envlis = py27,py34
[testenv:py27]
changedir = tests
# Installe coverage dans l'environnement virtuel
deps =
coverage
# Commandes externes à l'environnement virtuel, pour éviter les warnings
whitelist_externals = open
# La documentation expliquant comment lancer la suite de tests Django est ici :
# https://docs.djangoproject.com/en/dev/internals/contributing/writing-code/unit-tests/
commands =
pip install -r requirements/py2.txt
coverage erase
coverage run --rcfile=.coveragerc --include=*site-packages/django/* runtests.py --settings=test_sqlite --parallel=1
coverage html
open coverage_html/index.html
[testenv:py34]
changedir = tests
deps =
coverage
whitelist_externals = open
commands =
pip install -r requirements/py3.txt
coverage erase
coverage run --rcfile=.coveragerc --include=*site-packages/django/* runtests.py --settings=test_sqlite --parallel=1
coverage html
open coverage_html/index.html
Pour lancer les tests, une commande suffit à présent :
(tox-django) tox
Il est également possible de préciser un environnement particulier :
(tox-django) tox -e py34
Conclusion
L'écosystème Python est très riche et nous offre de nombreux outils pour d'une part nous faciliter la vie en tant que développeur, et d'autre part nous aider à produire du code propre et maintenable. À utiliser sans modération !
Pour aller plus loin avec Python, n'hésitez à venir nous rencontrer lors de nos sessions de formation Python.
Formations associées
Actualités en lien
Makina Corpus est sponsor de la PyConFR 2024
Le soutien de Makina Corpus à la PyConFR 2024, qui se tient du 31 octobre au 3 novembre 2024 à Strasbourg, reflète ses valeurs de partage et d’innovation, et son engagement envers la communauté dynamique et ouverte de Python.
Revoir les webinaires : découverte de l’outil CANARI-France
L’application CANARI-France est destiné aux acteurs agricoles afin de calculer des indicateurs agro-climatiques à partir de projections climatiques. Découvrer en le replay des 4 webinaires organisés par Solagro et l’ADEME.
Utiliser des fonctions PostgreSQL dans des contraintes Django
Cet article vous présente comment utiliser les fonctions et les check constraints
PostgreSQL en tant que contrainte sur vos modèles Django.