

Vous cherchez peut être les archives ?


Ceci dit, ça aurait pu être moins pire : le bureau aurait pu être vernis.
Calme, cool, zeeen, lexomiiil.
J’étais en train de rédiger un billet sur la PyCon FR 2008 quand Sunny m’a parlé du sien, et du coup, comme je suis un gros flemmard, je vais simplement faire un lien sur son blog : Pycon FR 2008.
Voici un petit billet pour donner des nouvelles du nouveau Bearnaise pour ceux que ça intéresse
Bon, déjà, pour les plus retardés niveau information, Dedibox nous ont livrés le serveur le mercredi 30 au soir. Au passage, nous avons dû resouscrire l’ancien serveur pour un mois vu le peu de temps entre la livraison du nouveau serveur et la fin du contrat de l’ancien. Depuis la livraison, Sunny et moi avons pas mal travaillé sur le serveur. Pour l’instant, voila ce qui est fait :
Ce qu’il manque
Bref, c’est pour très bientôt, encore un peu de patience :-)
Entre ma vie, la migration de Bearnaise (qui tarde un peu trop d’ailleurs, merci Free.), et le projet scolaire que je dois terminer pour la rentrée, je m’ennuyais un peu. Alors j’ai décidé de reprendre un vieux projet que j’avais entamé il y a fort longtemps avec Swater : un analyseur de logs de serveurs HTTP.
L’idée est de faire un analyseur de logs extremement modulaire afin de pouvoir ajouter ou retirer à souhait les traitements qui seront effectués sur les fichiers. Pour résumer le fonctionnement, il y a d’un coté des modules d’analyse genre “visiteurs”, “referers”, “hits”, etc. qui s’occupent de collecter des données sur chaques lignes des fichiers de logs. De l’autre coté, un module de rendu (genre “html”, “mail”, “texte”) qui lui s’occupe comme son nom l’indique si bien, du rendu du rapport de résultats.
Le projet est déjà bien entamé, et je compte releaser une première version très bientôt. J’ai fais quelques tests de performances pour avoir une idée (pour l’instant, ce n’est pas optimisé). Condition des tests : sur mon portable, Core Duo 1.66Ghz, 1Go de RAM (mais l’utilisation par le programme de la ram était minime), fichiers de logs du serveur http de Bearnaise, un peu plus d’un an pour 1231699 lignes.
Traitement des lignes relatives au domaine “inaps.org” avec un seul module d’analyse actif et en mode verbeux : time python s.py -m inaps.org -d 01012006 -e 99999 -v html visitors logs/*
Résultat : 132.91user 0.58system 2:16.75elapsed 97%CPU (0avgtext+0avgdata 0maxresident)k
Traitement des lignes relatives a tous les domaines avec un seul module d’analyse actif et en mode verbeux : time python s.py -d 01012006 -e 99999 -v html visitors logs/*
Résultat : 144.67user 4.52system 2:33.67elapsed 97%CPU (0avgtext+0avgdata 0maxresident)k
Traitement des lignes relatives a tous les domaines avec deux modules d’analyse actifs et en mode verbeux : time python s.py -d 01012006 -e 99999 -v html visitors,referers logs/*
Résultat : 168.98user 5.69system 3:05.21elapsed 94%CPU (0avgtext+0avgdata 0maxresident)k
Traitement des lignes relatives a tous les domaines avec deux modules d’analyse actifs et en mode silencieux : time python s.py -d 01012006 -e 99999 -q html visitors,referers logs/*
Résultat : 155.58user 0.24system 2:35.86elapsed 99%CPU (0avgtext+0avgdata 0maxresident)k
Même si ces tests ne sont pas hyper démonstratifs (ils dépendent des modules activés), ils donnent quand même une idée de la vitesse d’exécution du truc (il faudrait que je regarde ce qui se fait à coté).
Si certains ont des suggestions, elles sont les bienvenues…
Bouygue télécom a annoncé au début du mois de mars une nouvelle option “data” illimitée pour faire comme ses petits copains (avec lesquels il s’entend si bien), l’option Web & Mail. Sauf que Bouygue à une conception un peu particulière de l’illimité :
Si c’est pas du joli foutage de gueule tout ça…
Flemme de me relire ce soir, je ferais ça demain…
![]()
SteamPresence est un petit programme que j’ai réalisé avec l’aide de Sunny (pour la classe SteamPresence qui parse tout le caca juteux du site de Steam). Ce programme permet de garder un oeil sur ses amis gamers inscrits sur steam pour les rejoindres quand ils sont en train de jouer. Une fois lancé, il se place dans la zone de notification et affiche une bulle verte ou rouge selon l’état de l’ami.
C’est très simple, il suffit de lancer le programme avec comme seul et unique argument l’identifiant de l’ami sur steam community. Par exemple, l’adresse de mon profil est http://steamcommunity.com/id/grillepain, mon identifiant est “grillepain”. Il faut donc que je lance le programme comme ceci : ./steam_presence.py grillepain.
Sous gnome, vous pouvez utiliser les “programmes au démarrage” pour lancer automatiquement steam_presence. Je n’ai pas testé sur d’autres environnements.
Sous Windows le programme fonctionne mais ne permet pas d’afficher le menu (je corrigerais ce bug à l’occasion).
Techniquement parlant, ce programme est fait en Python (étonnant ;)) avec PyGTK (sans glade cette fois, pas utile). Pour sa classe SteamPresence, Sunny à utilise Beautiful Soup, un module python qui permet de parser “facilement” du html tout crado. Ah oui, et il est sous GPL.
La version de développement :
svn checkout svn://dev.inaps.org/inaps/steam_presence/trunk/ .
La release 1.0 :
svn checkout svn://dev.inaps.org/inaps/steam_presence/tags/1.0/ .
Direction le miroir bearnaise en ftp ou http, choisisez l’archive qui vous convient.
La boucle for en python ne fonctionne pas comme dans la majorité des autres langages de programmation. Elle permet de parcourir les objets “itérables”, c’est à dire, de manière générale, les chaines, les listes, les tuples et les dictionnaire. En réalité, la boucle for à besoin d’un objet iterator pour fonctionner. Cet objet possède une méthode next() qui renvoit à tour de rôle chacunes des valeurs que doit renvoyer l’objet pour chaque itération, et déclenche une exception StopIteration quand il arrive au bout. Petit exemple avec une liste :
>>> liste = ['Python', 'c\'est', 'bon']
>>> iterateur = liste.__iter__()
>>> iterateur
<listiterator object at 0x808968c>
>>> iterateur.next()
'Python'
>>> iterateur.next()
"c'est"
>>> iterateur.next()
'bon'
>>> iterateur.next()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
Comme vous pouvez le constater, chaque liste possède une méthode __iter__() qui retourne un objet iterator. Cet objet peut aussi être obtenu grace à la primitive iter(objet). On peut donc conclure qu’un objet itérable est un objet qui possède une méthode __iter__() qui retourne elle même un objet iterator.
En python, on ne se soucie pas de savoir si tel objet est de tel type, mais plutôt de savoir si l’on peut faire telle chose avec tel objet. On appel cela le duck typing : “Si ça marche comme un canard, que ça fait coin coin comme un canard, alors on peut appeler ça un canard”. Il est donc possible de créer très simplement un itérateur, et par extension un objet itérable :
>>> class Iterateur:
... i = 0
... def next(self):
... if self.i >= 10: raise StopIteration
... self.i += 1
... return 2**self.i
... def __iter__(self): return self
...
>>> objet_iterateur = Iterateur()
>>> for i in objet_iterateur: print i
...
1
2
4
8
16
32
64
128
256
512
Les générateurs sont une manière de créer des itérateurs. Il existe deux moyens d’utiliser les générateurs : au travers d’une fonction en utilisant le mot clé yield au lieu de return et en utilisant les “generator expressions” qui ressemblent à la définition de liste par “list comprehension”.
Puisqu’un petit exemple vaut mieux qu’un beau discours :
>>> def iterateur():
... for i in xrange(10):
... yield 2**i
...
>>> for i in iterateur(): print i
...
1
2
4
8
16
32
64
128
256
512
Et de manière plus concise avec les “generator expressions” (voir mon billet sur la compréhension de liste pour voir des exemples de la syntaxe générale, le seul différence résidant dans l’utilisation des parenthèses au lieu des crochets) :
>>> for i in (2**x for x in xrange(10)): print i
...
1
2
4
8
16
32
64
128
256
512
Comprendre les itérateurs et les générateurs permet de rendre son code plus concis et de mieux comprendre le fonctionnement de Python avec les objets itérables.
Python 3000, la prochaine version de Python, va supprimer un certain nombre de primitives pourtant bien utiles, tels que map() et filter(). A la place, la solution recommandée est l’utilisation des “list comprehension”, où en francais, compréhension de liste. Wikipedia nous propose cette définition :
Une liste, comme un ensemble, peut-être définie par la donnée d’une propriété caractéristique de ses éléments, on dit qu’on l’a définie en compréhension. Comme cette construction offre des avantages de lisibilité et de concision, certains langages de programmation proposent donc la possibilité de définir une liste par une propriété caractéristique et l’on appelle cela la compréhension de liste.
Avant de débuter avec les exemples, voici la grammaire des compréhension de liste en Python telle qu’elle est donnée dans la documentation :
test ::= and_test ( "or" and_test )* | lambda_form testlist ::= test ( "," test )* [ "," ] list_display ::= "[" [listmaker] "]" listmaker ::= expression ( list_for | ( "," expression )* [","] ) list_iter ::= list_for | list_if list_for ::= "for" expression_list "in" testlist [list_iter] list_if ::= "if" test [list_iter]
Trouver les 10 premières puissances de 2, avec map :
map(lambda x: 2**x, xrange(10))
Avec la compréhension de listes :
[2**x for x in xrange(10)]
Trouver les nombres pairs parmis les nombres de 0 à 9, avec filter() :
filter(lambda x:x%2 == 0, xrange(10))
Avec la compréhension de listes :
[x for x in xrange(10) if x%2==0]
Trouver la puissance de deux des nombres pairs de 0 à 9 (oui c’est totalement inutile), avec map() et filter() :
map(lambda x:2**x, filter(lambda x:x%2==0, xrange(10)))
Et avec les compréhension de listes :
[2**x for x in xrange(10) if x%2==0]
Un peu plus compréhensible non ?
On reprend l’exemple des puissances de deux, mais on veut renvoyer cette fois ci, à la fois le nombre calculé, et sa puissance :
[(x, 2**x) for x in xrange(10)]
Et avec un for pour gérer l’affichage :
for n, v in [(x, 2**x) for x in xrange(10)]:
print "2^%s = %s" % (n, v)
Résultat :
2^0 = 1
2^1 = 2
2^2 = 4
2^3 = 8
2^4 = 16
2^5 = 32
2^6 = 64
2^7 = 128
2^8 = 256
2^9 = 512
Pratique !