Derniers billets de blog
Bien configurer son environnement de développement Python : Standardiser l'exécution des tests avec tox. Partie 4
Cet article fait partie fait partie d'une série d'articles présentant quelques bonnes pratiques qui vous permettront d'avoir un environnement de développement Python aux petits oignons :
- Les environnements virtuels. Partie 1
- Personnaliser le script de démarrage du shell Python. Partie 2
- Valider son code Python avec flake8. Partie 3
- Standardiser l'exécution des tests avec tox. Partie 4
Standardiser l'exécution des tests avec tox
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
Une collection de fontes libres, prêtes à l'emploi et optimisées pour le web
alexbrush-regular
calendas-plus-regular
droidsans-bold
droidsans-regular
grandhotel-regular
lato-bold
lato-italic
lato-regular
leaguegothic-regular
merriweather-bold
merriweather-regular
opensans-bold
opensans-italic
opensans-light
opensans-regular
- Although never is often better than *right* now.
- If the implementation is hard to explain, it's a bad idea.
- If the implementation is easy to explain, it may be a good idea.
- Namespaces are one honking great idea -- let's do more of those!
Bien configurer son environnement de développement Python : Valider son code Python avec flake8. Partie 3
Cet article fait partie fait partie d'une série d'articles présentant quelques bonnes pratiques qui vous permettront d'avoir un environnement de développement Python aux petits oignons :
- Les environnements virtuels. Partie 1
- Personnaliser le script de démarrage du shell Python. Partie 2
- Valider son code Python avec flake8. Partie 3
- Standardiser l'exécution des tests avec tox. Partie 4
Installation de 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).
# Créons un projet dédié mkproject test-flake8 (test-flake8) cdproject # Installation de flake8 (test-flake8) pip install flake8
Valider son code Python avec flake8
Une fois installé, flake8 peut être invoqué sur un module Python ou un dossier complet.
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, ...).
Bien configurer son environnement de développement Python : Personnaliser le script de démarrage du shell Python. Partie 2
Cet article fait partie fait partie d'une série d'articles présentant quelques bonnes pratiques qui vous permettront d'avoir un environnement de développement Python aux petits oignons :
- Les environnements virtuels. Partie 1
- Personnaliser le script de démarrage du shell Python. Partie 2
- Valider son code Python avec flake8. Partie 3
- Standardiser l'exécution des tests avec tox. Partie 4
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 project (project) pip install requests Django (project) python [...] Virtualenv 'project' contains: 'Django', 'requests' Use Python startup script : ~/python_startup_script.py (project) >>> 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'}
Bien configurer son environnement de développement Python : Les environnements virtuels. Partie 1
Cet article fait partie fait partie d'une série d'articles présentant quelques bonnes pratiques qui vous permettront d'avoir un environnement de développement Python aux petits oignons :
- Les environnements virtuels. Partie 1
- Personnaliser le script de démarrage du shell Python. Partie 2
- Valider son code Python avec flake8. Partie 3
- Standardiser l'exécution des tests avec tox. Partie 4
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
Dans la prochaine partie, nous verrons comment configurer le script de démarrage du shell Python.
Plone 5 : Inclure du code avec la coloration synthaxique (restructuredText)
Coloration syntaxique avec Pygments
Introduction à Pygments
La coloration syntaxique permet de donner une couleur et un style particulier à chaque élément constituant un code source informatique, l'objectif étant de rendre ce code plus lisible et agréable à lire.
Pygments est une library Python qui permet la coloration syntaxique d'un très grand nombre de langages informatiques tel que Python, HTML, CSS, Javascript, PHP, Ruby, etc. Cet outil peut être utilisé directement avec la ligne de commande ou en tant que librairie intégrée dans un projet, permettant ainsi l'affichage de codes sources informatiques dans un site web, un wiki, un forum, etc.
Installer Pygments
Rien de plus simple, dans votre environnement virtuel Python :
pip install pygments
Générer la version HTML d'un "bout de code"
Soit le fichier code.py contenant le code Python suivant :
# Fibonacci numbers def fib(n): # write Fibonacci series up to n a, b = 0, 1 while b < n: print(b, end=' ') a, b = b, a+b print()
La version HTML de ce code s'obtient avec la commande suivante :
pygmentize -f html -l python -o code.html code.py
Où :
- -f est le format de sortie souhaité (ici html)
- -o est le nom du fichier de sortie
- -l est le module utilisé pour parser le code, appelé lexer (ici python)
Le code HTML ainsi généré est le suivant :
<div class="highlight"><pre><span class="c1"># Fibonacci numbers</span> <span class="k">def</span> <span class="nf">fib</span><span class="p">(</span><span class="n">n</span><span class="p">):</span> <span class="c1"># write Fibonacci series up to n</span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span> <span class="k">while</span> <span class="n">b</span> <span class="o"><</span> <span class="n">n</span><span class="p">:</span> <span class="k">print</span><span class="p">(</span><span class="n">b</span><span class="p">,</span> <span class="n">end</span><span class="o">=</span><span class="s1">' '</span><span class="p">)</span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span> <span class="o">=</span> <span class="n">b</span><span class="p">,</span> <span class="n">a</span><span class="o">+</span><span class="n">b</span> <span class="k">print</span><span class="p">()</span> </pre></div>
Pygments offres d'autres options pour améliorer le résultat, tel que l'ajout des numéros de ligne ou encore la génération d'un ficher HTML complet directement utilisable dans un navigateur.
Générer la feuille de style CSS : pygments.css
Le code HTML généré par Pygments n'inclu pas les informations de style CSS mais uniquement des balises <span> avec les classes nécessaires (ex: <span class="c1"># Fibonacci numbers</span>). Il nous faut par conséquent générer la feuille de styles CSS nécessaire au bon affichage, à inclure dans notre page web :
Pour générer cette feuille de style, utilisez la commande suivante :
pygmentize -f html -S colorful > pygments.css
Le fichier pygments.css contient alors (extrait) :
.hll { background-color: #ffffcc } .c { color: #888888 } /* Comment */ .err { color: #FF0000; background-color: #FFAAAA } /* Error */ .k { color: #008800; font-weight: bold } /* Keyword */ .o { color: #333333 } /* Operator */ .ch { color: #888888 } /* Comment.Hashbang */ .cm { color: #888888 } /* Comment.Multiline */ .cp { color: #557799 } /* Comment.Preproc */ ...
Intégrer et utiliser Pygments dans Plone
Écrire ses articles dans le format "text/restructured"
Pour pouvoir utiliser le format "text/restructured" dans l'éditeur WYSIWYG de Plone, il est nécessaire de l'activer dans la page de configuration "Configuration du site > Contenu > Formatage du texte": cochez "text/restructured".
Le format apparaît alors dans la liste de choix se situant juste en dessous de l'éditeur WYSIWYG.
Ajouter Pygments dans le buildout du projet
# buildout.cfg file [buildout] eggs = Plone Pillow Pygments ... [versions] Pygments = 2.0.2 ...
bin/buildout
Saisir du code source en "text/restructured" dans un article
Exemple pour du code Python :
.. sourcecode:: python # Fibonacci numbers def fib(n): # write Fibonacci series up to n a, b = 0, 1 while b < n: print(b, end=' ') a, b = b, a+b print()
En savoir plus sur la directive sourcecode.
Le code HTML généré par Plone est le suivant :
<pre class="code python literal-block"><span class="comment"># Fibonacci numbers</span> <span class="keyword">def</span> <span class="name function">fib</span><span class="punctuation">(</span><span class="name">n</span><span class="punctuation">):</span> <span class="comment"># write Fibonacci series up to n</span> <span class="name">a</span><span class="punctuation">,</span> <span class="name">b</span> <span class="operator">=</span> <span class="literal number integer">0</span><span class="punctuation">,</span> <span class="literal number integer">1</span> <span class="keyword">while</span> <span class="name">b</span> <span class="operator"><</span> <span class="name">n</span><span class="punctuation">:</span> <span class="keyword">print</span><span class="punctuation">(</span><span class="name">b</span><span class="punctuation">,</span> <span class="name">end</span><span class="operator">=</span><span class="literal string">' '</span><span class="punctuation">)</span> <span class="name">a</span><span class="punctuation">,</span> <span class="name">b</span> <span class="operator">=</span> <span class="name">b</span><span class="punctuation">,</span> <span class="name">a</span><span class="operator">+</span><span class="name">b</span> <span class="keyword">print</span><span class="punctuation">()</span> </pre>
Générer la feuille de style CSS : pygments.css
Le code HTML généré par Pygments n'inclu pas les informations de style CSS mais uniquement des balises <span> avec les classes nécessaires (ex: <span class="c1"># Fibonacci numbers</span>). Il nous faut par conséquent générer la feuille de styles CSS nécessaire au bon affichage :
cd <zeocluster-directory>
bin/pygmentize -f html -S colorful -a pre.code > pygments.css
Cette commande va générer un fichier pygments.css utilisant le thème "colorful" pour le sélecteur "pre.code" afin de ne pas styler d'autres éléments de notre page.
Malheureusement l'intégration de cette feuille de style dans Plone ne suffira pas pour que la coloration soit effective sur notre code :(
En effet, le code HTML généré par Plone contient des noms de classe css longs, comme par exemple <span class="comment"># Fibonacci numbers</span> alors que la feuille de style fournit par Pygments permet de traiter des noms de classe css courts comme <span class="c1"># Fibonacci numbers</span>.
- Un contributeur sur stackoverflow propose une solution à ce problème
- en utilisant un script Python qui permet de générer une feuille de style Pygments contenant à la fois les noms de classe css courts et les noms de classe css long, solutionnant ainsi notre problème.
Intégrer pygments.css dans Plone
Pour finaliser le tout il ne reste plus qu'à intégrer la feuille de style Pygments dans Plone.
En ce qui me concerne je l'ai ajouté dans mon thème et je l'ai inclu dans mon fichier less principal avec la directive "(css)" qui permet d'inclure tel quel du code CSS dans un fichier less :
// Pygments @import (css) "pygments.css";
Et voilà !
Le présent article utilise cette technique !