Makina Blog

Le blog Makina-corpus

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

Aller plus loin avec pip

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

Aller plus loin avec tox


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

Formations Python

Formation Python

À distance (FOAD) Du 29 janvier au 2 février 2024

Voir la formation

Formations Django

Formation Django initiation

Nantes Du 12 au 14 mars 2024

Voir la formation

Actualités en lien

Image
Django PostgreSQL
07/11/2023

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.

Voir l'article
Image
Encart Django
06/11/2023

Comment migrer vers une version récente de Django ?

Que ce soit pour avoir les dernières fonctionnalités ou les correctifs de sécurité, rester sur une version récente de Django est important pour la pérennité de son projet.

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