Conférences
Nous avons ensuite assistés à de nombreuses conférences sur les deux jours
suivants, et voici un petit résumé de ce que nous avons appris :
Les infos en vrac
- Python 3.3 c'est bon mangez-en
- Si vous utilisez Django, utilisez Django Debug Toolbar, South et Sentry
- Django 1.5 est compatible avec Python 3, les tests passent et il est possible
de commencer à porter ses applications dessus (release fin 2012).
- Django 1.6 supportera officiellement Python 3 à l'horizon Novembre 2013.
- Mercurial continue sa progression avec des améliorations sur les
performances et le rebase.
Déployer avec fabric
Vous connaissez peut-être déjà fabric c'est un module Python qui
permet d'exécuter des règles écrites en python sur un serveur distant
en utilisant ssh
En gros, le fabfile est le makefile python over ssh.
Ronan Amicel à eu la bonne idée de
rajouter là dessus des recettes de provisioning (c'est à dire des
règles permettant d'installer et de configurer la machine distante).
Cela permet notamment d'installer son appli sur une VM vierge.
Ce n'est pas réellement un concurrent à Chef, Puppet ou Salt mais
plutôt une couche intermédiaire permettant d'aller un peu plus loin
avec un fabfile de manière propre et sans overhead.
Voilà à quoi ça ressemble :
from fabric.api import *
from fabtools import require
import fabtools
@task
def setup():
# Require some Debian/Ubuntu packages
require.deb.packages([
'imagemagick',
'libxml2-dev',
])
# Require a Python package
with fabtools.python.virtualenv('/home/myuser/env'):
require.python.package('pyramid')
# Require an email server
require.postfix.server('example.com')
# Require a PostgreSQL server
require.postgres.server()
require.postgres.user('myuser', 's3cr3tp4ssw0rd')
require.postgres.database('myappsdb', 'myuser')
# Require a supervisor process for our app
require.supervisor.process('myapp',
command='/home/myuser/env/bin/gunicorn_paster /home/myuser/env/myapp/production.ini',
directory='/home/myuser/env/myapp',
user='myuser'
)
# Require an nginx server proxying to our app
require.nginx.proxied_site('example.com',
docroot='/home/myuser/env/myapp/myapp/public',
proxy_url='http://127.0.0.1:8888'
)
# Setup a daily cron task
fabtools.cron.add_daily('maintenance', 'myuser', 'my_script.py')
REST in SPORE
SPORE est une spécification de description complète, au format JSON,
d'un service REST.
Ce fichier peut-être consommé pour générer automatiquement un client
REST pour cette API.
Il existe des générateur de client SPORE dans de nombreux languages.
En Python, l'Université de Strasbourg développe actuellement Spyre
Voici un exemple de fichier SPORE :
{
"name": "Middle Earth Web API",
"authority": "MORDOR:Sauron",
"version": "1.0",
"formats": [
"json"
],
"methods": {
"get_ring": {
"path": "/rings/:id.:format",
"required_params": [
"id",
"format"
],
"method": "GET",
"authentication": true,
"expected_status": [200, 403]
},
"get_precious": {
"path": "/rings/9.:format",
"required_params": [
"format"
],
"authentication": true,
"method": "GET",
"expected_status": [200, 403]
}
}
}
Pour voir un exemple de server et de client implémentant cette
spécification en Python : https://github.com/agrausem/mordor
Suite à cette présentation, Alexis Metaireau à commencer une feature
pour cornice permettant de générer automatiquement le fichier SPORE à
partir du service développé avec Cornice.
PyBABE et les flux de données
PyBabe est conçu pour gérer de gros fichiers de données (CSV, Exel,
ODS) et de pouvoir les manipuler sans tout charger en mémoire pour
faire des requêtes dessus (extraire des colonnes) ou pour les convertir
simplement d'un format à l'autre.
PyBabe est capable de récupérer les fichiers over DB, FTP, Http, Email, S3, ...
Des fichiers zippés, Gzippé, CSV, Exel, ...
Voici un exemple simple d'utilisation :
# Recupére un fichier CSV de S3, le décompresse, cache en local
babe = babe.pull(url="s3://myapp/mydir 2012-07-07_*.csv.gz",cache=True)
# Recupère l’IP dans le champs IP, trouve pas geoip le pays
babe = babe.geoip_country_code(field="ip", country_code="country", ignore_error_True)
# Récupère le user agent, et stocke le nom du navigateur
babe = babe.user_agent(field="user_agent", browser="browser")
# Ne garde que les champs pertinents
babe = babe.filterFields(fields=["user_id", "date", "country", "user_agent"])
# Stocke le résultat dans une base de donnée
babe.push_sql(database="mydb", table="mytable", username="…");
Voici un autre exemple ou PyBabe gére un important flux de données :
babe = Babe()
# Recupére un gros fichier csv
babe = babe.pull(filename="mybigfile.csv")
# Effecture un tri "disk-based", par paquet de 100.000 lignes
babe = babe.sortDiskBased(field="uid", nsize=100000)
# Calcule un regroupement par uid
# Calcule la somme des revenues par utilisateurs.
babe = babe.groupBy(field="uid", reducer=lambda x, y: (x.uid, x.amount + y.amount))
# Join avec le résultat d’une requete sql pour recupérer des meta information sur les utilisateurs
babe = babe.join(Babe().pull_sql(database="mydb", table="user_info", "uid", "uid")
# Stocke le résultat du rapport dans un fichier Excel !!
babe.push (filename="reports.xlxs");
Le projet a l'air très intéressant, mais en rédigeant cette article,
je n'ai trouvé aucune documentation.
Plus d'informations : https://github.com/fdouetteau/PyBabe
Cornice : Vos webservices simplifiés
Générez vos API et ayez automatiquement une documentation ainsi que
votre fichier SPORE. Vous pouvez ensuite brancher votre API sur le
système d'URL de votre choix Werkzeug, Django ou Pyramid.
Pour faire simple
$ pip install cornice
$ paster create -t cornice project
Ensuite il suffit de modifier le fichier views.py :
import json
from cornice import Service
values = Service(name='foo', path='/values/{value}',
description="Cornice Demo")
_VALUES = {}
@values.get()
def get_value(request):
"""Returns the value.
"""
key = request.matchdict['value']
return _VALUES.get(key)
@values.post()
def set_value(request):
"""Set the value.
Returns *True* or *False*.
"""
key = request.matchdict['value']
try:
_VALUES.set(key, json.loads(request.body))
except ValueError:
return False
return True
Pour plus d'informations : http://packages.python.org/cornice
Tornado : Et le web asynchrone devient possible
Si vous devez faire du long polling ou demander des informations à des
API distances telles que Facebook, Twitter, ... vous devez jeter un
œil à Tornado.
Tornado vous permet de mettre en place vos applis de web asynchrone
sans remplir vos workers WSGI et sans faire exploser votre serveur en
le remplissant de requêtes bloquantes.
Par contre le mode asynchrone n'est pas compatible avec WSGI.
Voici un exemple de requête asynchrone :
class MainHandler(tornado.web.RequestHandler):
@tornado.web.asynchronous
def get(self):
http = tornado.httpclient.AsyncHTTPClient()
http.fetch("http://friendfeed-api.com/v2/feed/bret",
callback=self.on_response)
def on_response(self, response):
if response.error: raise tornado.web.HTTPError(500)
json = tornado.escape.json_decode(response.body)
self.write("Fetched " + str(len(json["entries"])) + " entries "
"from the FriendFeed API")
self.finish()
Tant que self.finish() n'est pas appelé la connexion HTTP ne se
termine pas, on peut donc utiliser un système de callback assez
sympathique.
Plus d'informations ici : http://www.tornadoweb.org/documentation/
La gestion des timezones en Python
La gestion des timezones est quelque chose d'assez compliqué.
Avec Python puisque cette notion évolue, la définition des timezones
est définie dans le package pytz qui est mis à jour à chaque
modification.
Il est conseillé de traiter tous les temps en UTC et de faire la modification lors de l'affichage.
Attention, une date seule ou une heure seule n'a pas de sens dans un environnement timezone aware.
Conclusion
Cette conférence fût, comme à son habitude, une excellente opportunité pour en
apprendre davantage sur notre métier, renforcer notre expertise, et surtout,
rencontrer et faire connaissance avec nos pairs !
Pour rappel, à l'exception d'une personne recrutée à la suite d'un stage, la
totalité de l'équipe Django à Novapost se connaissait bien avant de travailler
ensemble.
Tout développeur passionné par son métier devrait participer à ce genre de
rencontres (il y en a aussi de plus spécifiques à Django), afin de parfaire
ses connaissances, découvrir de nouvelles pistes d'amélioration, et se tenir à
jour sur l'état de l'art !
Un énorme merci à toute l'équipe d'organisation, et un grand bravo à Nelle
Varoquaux, la nouvelle présidente de l'association AFPY qui chapeaute cette
rencontre depuis maintenant plusieurs années.
Merci enfin à tous les participants que nous avons pu croiser, avec qui nous
avons pu échanger, et qui nous ont parfois donné d'excellentes idées pour
rendre notre produit encore meilleur.
À l'année prochaine !