django monte en puissance

Posté le 09/04/2008 sous django pycon afpy

Je crois que django a de l'avenir. Google viens de sortir son app engine qui s'appuie en grande partie sur django et le WSGI (ça me fait penser qu'il faudrait que je prépare ma conf pour pycon un jour). C'est plutôt très bon signe pour django et pour python plus généralement, d'ailleurs. Google se lance dans le mass-hosting et c'est en python que ça se fait. Cet hébergement gratuit grand publique est-il le début de la vrai vulgarisation de python ? On ne peut que l'espérer ! Jusqu'à présent, objectis était le seul hébergeur gratuit (au monde ?) a proposer une solution python gratuite. Cela manquait vraiment.

Suite à cette annonce, j'ai eu aussi l'occasion de découvrir playlive.fm. Un site musico-social 2.0 basé sur django. Le résultat est joli (j'ai eu une invite, héhé) et j'ai été agréablement surpris de voir que Hocus-Pocus (je suis super fan, ils tuent. naoned représente !) est déjà présent sur la plate-forme.

svn: le futur du CMS !!!

Posté le 01/04/2008 sous zope3

Vous êtes comme moi je suis sûr. Editer des document dans des éditeur WYSIWYG, ça vous saoul au plus haut point. Personnellement, je préfère de loin un bon éditeur et du reStructuredText.

La solution je l'avais depuis longtemps. Stocker les billets de mon blog dans un svn et les publier avec un framework quelconque. Ca fait un moment maintenant que j'utilise Zope3 pour ça, mais le code était assez dégueulasse. Je me suis donc dit que si je mettais tout ça un peu au propre, cela pourrait servir à d'autres. Je me suis donc lancé dans un énorme week-end de geeking. le résultat est gp.svnfolder, un package Zope3 permettant de publier un répertoire svn contenant des documents en reStructuredText.

Voyons plutôt. Il nous faut une repository valide:

>>> import os
>>> from os.path import split
>>> curdir = split(split(os.getcwd())[0])[0]
>>> repos = os.path.join(curdir, 'tests', 'rstfolder')

Avec ça, on peut instancier un dossier svn:

>>> from gp.svnfolder.folder import SVNFolder
>>> folder = SVNFolder()
>>> folder.__name__ = 'blog'
>>> folder.path = u'file://%s' % repos

Et en voir le contenu:

>>> sorted(folder.keys())
[u'doc.rst', u'doc2.rst']

Et accéder aux fichiers:

>>> file = folder['doc.rst']
>>> print file.data
Document 1
==========
<BLANKLINE>

Ensuite il suffit d'utiliser les vues fournies pour rendre ces fichiers en html.

Voila. Je penses qu'avec un peu de motivation je pourrais facilement le rendre compatible avec Mercurial et Bazaar mais ça suffit à faire mon bonheur :)

Monter un environnement python avec zc.buildout

Posté le 20/03/2008 sous python buildout

zc.buildout est un utilitaire créer par Jim Fulton, le papa de Zope. L'étendue des capacités de zc.buildout est énorme et mériterais un livre entier.

Cependant, voici un petit exemple pour se monter un environnement de paquets/binaire python avec un simple petit fichier de configuration.

Tout d'abord, nous allons nous créer un virtualenv afin de ne vraiment pas polluer notre distribution:

gawel@Stacy:~$ virtualenv --no-site-packages py
New python executable in py/bin/python
Installing setuptools.............done.

Si vous n'avez pas virtualenv, installez setuptools et virtualenv sur votre système. D'après moi, ce sont les deux seuls packages qui mérite d'être installé globalement, pour tout le système.

On va ensuite installer zc.buildout dans notre environnement:

gawel@Stacy:~$ cd py
gawel@Stacy:~/py$ ./bin/easy_install zc.buildout
Searching for zc.buildout
...
Finished processing dependencies for zc.buildout

Parfait, maintenant, initialisons l'environnement de zc.buildout:

gawel@Stacy:~/py$ ./bin/buildout init
Creating '/Users/gawel/py/buildout.cfg'.
Creating directory '/Users/gawel/py/parts'.
Creating directory '/Users/gawel/py/develop-eggs'.
Generated script '/Users/gawel/py/bin/buildout'.

Puis on édite le fichier buildout.cfg pour qu'il ressemble à ça:

gawel@Stacy:~/py$ cat buildout.cfg
[buildout]
parts = eggs

[eggs]
recipe = zc.recipe.egg
eggs=
    ipython
    i18ndude
    ZopeSkel
    IngeniSkel
    iw.releaser

Vous pouvez mettre absolument n'importe quel egg dans l'option eggs. La seule contrainte est que ceux-ci se trouvent sur pypi.

On lance la construction du buildout:

gawel@Stacy:~/py$ ./bin/buildout
Installing eggs.
...
Generated script '/Users/gawel/py/bin/ipython'.
Generated script '/Users/gawel/py/bin/pycolor'.
Generated script '/Users/gawel/py/bin/i18ndude'.
Generated script '/Users/gawel/py/bin/project_deploy'.
Generated script '/Users/gawel/py/bin/project_release'.
Generated script '/Users/gawel/py/bin/project_diff'.

J'ai maintenant tout mes binaires dans le dossier bin/ de l'environnement:

gawel@Stacy:~/py$ ls bin/
activate          easy_install-2.4* project_deploy*   pycolor*
buildout*         i18ndude*         project_diff*     python*
easy_install*     ipython*          project_release*  python2.4@

Le must, c'est que je peux importer chacun de ses paquets dans mon ipython:

gawel@Stacy:~/py$ ./bin/ipython
In [1]: import i18ndude

In [2]: dir i18ndude
------> dir(i18ndude)
Out[2]: ['__builtins__', '__doc__', '__file__', '__name__', '__path__']

Vous pouvez bien sur ajouter des eggs dans votre buildout.cfg puis relancer ./bin/buildout pour qu'il soit prit en compte.

Ceci est une simple introduction à zc.buildout. On peut faire bien mieux, je sais. Mais ça deviendrais compliquer de tout expliquer dans un simple post :)

Simplement, Je trouve ça tellement pratique pour tester rapidement un package que je voulais en faire bénéficier tous ceux qui ne connaissent même pas l'existence de zc.buildout.

Traduire un package Plone 3

Posté le 15/02/2008 sous zope plone3

Je n'ai pas creusé plus que ça, mais apparemment il y a de beaux conflits entre zope.i18n et PlacelessTranslationService. Du coup, tant que l'on veut ajouter des traductions à un domaine non existant, se servir de zope.i18n ne pose pas de problème. Par contre, si l'on désire ajouter des traductions au domaine plone par exemple, ça ce complique.

Le seul moyen que j'ai pu trouver après quelques heures d'introspection est d'enregistrer un .po qui se trouve hors du répertoire locales (si vous le mettez dedans, ça casse tout) lors de l'initialisation du paquet. Cela donne un bout de code horrible qui me ferais presque honte... Voyez plutôt le contenu de mon __init__.py:

def initialize(context):
    """Initializer called when used as a Zope 2 product."""
    context._ProductContext__app.Control_Panel.TranslationService._load_i18n_dir(os.path.dirname(__file__)+'/i18n')

Alors, oui, c'est dégueulasse, mais ça marche.

Utiliser zope.sendmail dans Zope 2

Posté le 11/02/2008 sous zope

Depuis que les sources de Zope3 sont incluse dans Zope2, il est vraiment dommage de ne pas utiliser au maximum ces possibilités.

Entre autre, il existe un package assez peu connu zope.sendmail qui permet d'envoyer des mails de façon asynchrone. Les mails sont stockés dans une mailbox puis envoyés par un thread séparé de Zope.

L'inconvénient de ce package est que tout est configurable, mais uniquement via du zcml. Le TODO indique que, oui, ça serait bien qu'un jour cela soit dans le zope.conf, mais en attendant...

Finalement, depuis qu'on a tendance à utiliser buildout (parce que quand même, ça arrache) il était super simple de créer une petite recette qui installe un bout de zcml dans le répertoire qui vas bien.

Le résultat est iw.recipe.sendmail. Simple, et efficace.

Un autre petit paquet, iw.mailhost, permet de patcher les produits MailHost et SecureMailHost afin d'utiliser zope.sendmail en lieu et place de smtplib. Il suffit de le placer dans un répertoire inclus dans le sys.path pour qu'il soit importé par le zcml généré par iw.recipe.sendmail

A noter que ceci a été éprouvé sous OSX, Linux et Windows. Enjoy !

Utiliser zope avec virtualenv

Posté le 17/10/2007 sous zope python

Virtualenv permets de créer un environement python indépendant de celui du système. C'est assez pratique lorsque l'on veut avoir plusieurs versions d'une même librairie.

Il est possible de l'utiliser avec Zope. C'est même très simple...

On install virtualenv avec easy_install:

~$ easy_install virtualenv

On s'extrait un Zope:

~$ tar xvzf Zope-2.X.X-final.tgz
~$ mv Zope-X.X.X-final myenv

On créer un virtualenv dans l'arborescence du Zope:

~$ virtualenv myenv
New python executable in myenv/bin/python
Installing setuptools......................done.
~$ source bin/activate
(myenv)$ which python
/home/gawel/myenv/bin/python

On utilise le python de l'environnement pour installer le Zope:

(myenv)~$ cd myenv
(myenv)~/myenv$ ./configure --with-python=bin/python

Using Python interpreter at bin/python

Configuring Zope installation

  - Zope top-level binary directory will be /opt/Zope-2.9.
  - Makefile written.

  Next, run make.

On le compile:

(myenv)~/myenv% make && make inplace

On peut ensuite créer des instances comme d'habitude. Ces instances utiliserons notre virtualenv.

Quand la poisse d'acharne

Posté le 17/09/2007 sous life

Enfin, une nouvelle semaine commence. Je ne sais pas ce que j'ai fais à celle passée pour qu'elle s'acharne autant sur moi. Aujourd'hui, c'est la première fois depuis une semaine qu'il ne m'arrive pas de sale coup. Je crois que je n'aurais échappé à rien.

Des bornes vélib' pleines m'obligeant à faire 2km alors que, au départ, j'étais à 500m de chez moi. Non mais, ces foutues bornes sont toujours vide quand je veux en prendre un à coté de chez moi ! Bon, ça fait faire du sport...

Une jeune femme qui se gourre (ahem) en me filant son numéro de téléphone. En la rappelant une semaine plus tard, je tombe sur une gamine de 15 ans. Je m'excuse, et j'oublie. Par contre, s'en suit un harcellement téléphonique de 3 jours par pas moins de 4 gamines n'ayant rien de mieux à faire pendant leurs cours que de faire beeper mon téléphone. Elle aurait pû s'y mettre toute seule, ça n'aurais fait qu'un coup de fil toute les 5mn. Mais non, il faut qu'elle fasse participer 3 de ses pimbêches de copines ! Je vous assure qu'a cet âge, elles ont un sacré rendement sur la touche Bis. Tout ça à cause d'un mauvais numéro. Si c'est pas de la poisse, je sais pas ce que c'est.

Du vol. Cette semaine, j'aurais laissé planer dans la nature: un t-shirt laissé 10mn dans un panier de vélib' dans une rue déserte à 2h du mat'. Mon téléphone portable et mon précieux iPod resté dans mon manteau que j'avais laissé traîner à quelques pas de moi. La malédiction s'acharne.

La carte vélib' (ouais, encore lui. ahem) qui refuse de m'en délivré un. Là, mon imagination virevolte: "Mais, heu, le dernier que j'ai pris c'était y a 3 jours". Je me voyait déjà payé ces trois jours à raison 4 euros de l'heure. J'avoue ne pas avoir eu le courage de faire l'addition...

Vous me direz que mes problèmes sont ridicules. Oui ! Ce ne sont d'ailleurs même pas des problèmes et c'est bien le drame. Je crois qu'il est plus facile à vivre d'avoir de vrai problèmes et de savoir comment les aborder que de vivre de tels événement face auquels ont est totalement impuissant. Juste parce qu'on à la poisse !

C'est le genre de billet que j'ai horreur d'écrire. Je trouve que ça n'as aucun intérêt de raconter sa vie. Mais bon, la prochaine fois que je passe une semaine vraiment pourrie ça me rappellera que j'ai vécu pire !

Les bornes vélib' sont sales

Posté le 08/08/2007 sous saleos

Vendredi dernier il faisait beau et bonheur, j'ai une borne vélib' à 10 mètres de chez moi. Je me dis donc: "Allez, un petit coup de vélo !".

Je tapotes donc sur le clavier de la borne vélib' pour obtenir un ticket journalier. Arrive le moment où on me demande ma carte bleu. Je l'introduis donc puis je saisis mon code. Et là, c'est le drame ! Cette foutu borne plante, puis reboot. Impossible de retirer ma CB. Petit coup de flip. Bon, à défaut de pouvoir la retirer et fuir, je saisis mon téléphone et je shoot !

http://www.gawel.biz/pub/photos/misc/borne_velib_sale.jpg

On s'en serait douté, pour que la borne reboot aussi inopinément, il ne pouvait s'agir que d'un saleos ! On se demande vraiment ou est l'intérêt de ne pas utiliser du libre alors que c'est probablement une application métier qui aurait très bien pu être écrite en C ou en python. Voila le résultat !

Ouverture du parc des batignolles

Posté le 19/07/2007 sous life extrem

A défaut du village olympique qui était prévu pour 2012, la ville de Paris à fait un bon gros parc dans le quartier des batignolles.

A l'intérieur on y trouve des espaces verts, des terrains de sport (basket,etc.) et surtout, ce qui personnellement m'intéresse un chouîlla plus, un "petit" skatepark. Pour l'instant il n'y a qu'une vaste air goudronnée avec une vague.

http://www.gawel.org/pub/photos/skate/five-O-batignolles.png

C'est super rigolo à skater. Je ne saurais que vous conseiller d'y passer. La courbe est un peu étrange. Tout petit rayon puis plan incliné. Le tout part du niveau du sol pour arriver à plus de 3 mêtres de haut. Ce qui est étrange c'est que le rayon de la courbe est le même quelque soit la hauteur.

Ce qui est bien c'est que, même si c'est une courbe, les streeteurs semble y trouver leurs compte. Si le reste des modules est aussi réussis, vas y avoir de quoi s'amuser :)

Les exceptions python

Posté le 03/07/2007 sous python

Les exceptions python sont toutes simple. Vous pouvez facilement créer les votre:

>>> class MonException(Exception):
...     """ Une exception """

Puis les propager:

>>> raise MonException('Bouh !')
Traceback (most recent call last):
...
MonException: Bouh !

Ca, c'est la base. Mais il y a des trucs plus rigolo à faire. Par exemple garder la trace d'une suite d'exceptions:

>>> class MultiException(Exception):
...     """ une exception contstitué de plusieurs autre """
...     def __init__(self):
...         Exception.__init__(self)
...         self.data = []
...     def __nonzero__(self):
...         return self.data and True or False
...     def __str__(self):
...         return ', '.join(['%s: %s' % (e.__class__.__name__,str(e)) for e in self.data])

Et voila ce que cela donne à l'utilisation. On fait une boucle dans laquelle une ou plusieurs exceptions peuvent se produire:

>>> exceptions = MultiException()
>>> for i in [1, 3, 0, 7, 1, 0]:
...     try:
...       a = 2/i
...     except Exception, e:
...       exceptions.data.append(e)

Puis on propage notre exception si elle n'est pas vide:

>>> if exceptions:
...     raise exceptions
Traceback (most recent call last):
...
MultiException: ZeroDivisionError: integer division or modulo by zero, ZeroDivisionError: integer division or modulo by zero

On voit bien ainsi que deux exceptions se sont produites et non une seule. On pourrait faire mieux. Par exemple conserver la pile de chaque exception, etc.

En fait, je n'ai rien inventé. C'est le principe utilisé par exemple dans Zope pour gérer la validation de formulaire (zope.app.form). Je trouve que c'est plutôt un bon concept. Après tout, une erreur de saisie c'est quelque chose qui engendre une erreur. Donc une exception :)