<?xml version="1.0" encoding="ISO-8859-15"?>
<feed version="0.3" xmlns="http://purl.org/atom/ns#"
      xmlns:dc="http://purl.org/dc/elements/1.1/">
  <title mode="escaped" type="text/html">programmation-python.org - Tarek Ziadé</title>
  <tagline>ATOM Feed - programmation-python.org - Tarek Ziadé</tagline>
  <link rel="alternate" type="text/html"
        href="http://programmation-python.org/sections/blog" />
  <id>tag:programmation-python.org:sections:blog</id>
  <generator url="http://cps-project.org" version="3">CPS</generator>
  <modified>2007-01-28 12:08:54</modified>

  <link rel="service.feed"
        href=" http://programmation-python.org/sections/blog/atomFeed"
        title="programmation-python.org - Tarek Ziadé"
        type="application/atom+xml" />
  <link rel="service.post"
        href=" http://programmation-python.org/sections/blog/postAtom"
        title="programmation-python.org - Tarek Ziadé"
        type="application/atom+xml" />
  <link rel="service.categories"
        href=" http://programmation-python.org/sections/blog/atomCategories"
        title="programmation-python.org - Tarek Ziadé"
        type="application/atom+xml" />

  
      <entry xmlns="http://purl.org/atom/ns#"
       xmlns:dc="http://purl.org/dc/elements/1.1/">
     
  <title mode="escaped" type="text/html">AfpySprint à Dijon</title>
  <link rel="alternate" type="text/html"
        href="http://programmation-python.org/sections/blog/2007_09_30_afpysprint-dijon" />
  <issued>2007-09-30T09:51:28Z</issued>
  <modified>2007-09-30T09:51:28Z</modified>
  <created>2007-09-30T09:51:28Z</created>
  <draft xmlns="http://purl.org/atom-blog/ns#">false</draft>
  <author>
    <name>tarek</name>
  </author>
  
  
    <dc:subject>afpy</dc:subject>
  
  
    <dc:subject>coding</dc:subject>
  
  
    <dc:subject>evenements</dc:subject>
  
  
  <summary type="text/html" mode="escaped">L'A.G. de l'Afpy organisée ce week-end à Dijon, s'est transformée en AfpySprint par manque de monde pour atteindre le quorum. Le nouveau bureau de l'association sera donc voté plus tard :)Entre deux restos et une dégustation de vins, nous avont bossé sur trois ateliers:préparation des JFP'08, qui a été l'occasion d'une démo par Seb de MinMap pour la prise de note, avec Freemind;création d'une ...</summary>

  <content type="text/html" mode="escaped"
           xml:space="preserve">L'A.G. de l'Afpy organisée ce week-end à Dijon, s'est transformée en AfpySprint par manque de monde pour atteindre le quorum. Le nouveau bureau de l'association sera donc voté plus tard :)&lt;br&gt;&lt;br&gt;Entre deux restos et une dégustation de vins, nous avont bossé sur trois ateliers:&lt;br&gt;&lt;ul&gt;&lt;li&gt;préparation des JFP'08, qui a été l'occasion d'une démo par Seb de MinMap pour la prise de note, avec &lt;a href="http://freemind.sourceforge.net/wiki/index.php/Main_Page"&gt;Freemind;&lt;/a&gt;&lt;br&gt;&lt;/li&gt;&lt;li&gt;création d'une application Django (afpy_jobs) pour les offres d'emplois du site, qui deviendra &lt;i&gt;jobs.afpy.org&lt;/i&gt; à terme;&lt;/li&gt;&lt;li&gt;reprise du taf sur mailwoman, qui doit nous permettre à terme de fusionner &lt;a href="http://www.gnu.org/software/mailman/index.html"&gt;mailman&lt;/a&gt; et le forum web du site.&lt;/li&gt;&lt;/ul&gt;&lt;br&gt;Pour info, l'association a maintenant son propre serveur dedibox, et vous pouvez suivre les devs sur le repository  : &lt;a href="http://trac.afpy.org/misc"&gt;http://trac.afpy.org/misc&lt;/a&gt;&lt;br&gt;</content>

  <id>tag:programmation-python.org:sections:blog:2007_09_30_afpysprint-dijon</id>
  <link rel="service.edit" type="application/atom+xml"
        href="http://programmation-python.org/sections/blog/2007_09_30_afpysprint-dijon/atom?2007_09_30_afpysprint-dijon"
        title="Edit Here - AfpySprint à Dijon" />
</entry>

  
  
      <entry xmlns="http://purl.org/atom/ns#"
       xmlns:dc="http://purl.org/dc/elements/1.1/">
     
  <title mode="escaped" type="text/html">Dijon capitale du V.. Libre !</title>
  <link rel="alternate" type="text/html"
        href="http://programmation-python.org/sections/blog/2007_09_13_dijon-capitale-du-v" />
  <issued>2007-09-13T08:11:28Z</issued>
  <modified>2007-09-13T08:11:28Z</modified>
  <created>2007-09-13T08:11:28Z</created>
  <draft xmlns="http://purl.org/atom-blog/ns#">false</draft>
  <author>
    <name>tarek</name>
  </author>
  
  
    <dc:subject>evenements</dc:subject>
  
  
  <summary type="text/html" mode="escaped">Hasard du calendrier, le mois de septembre sera riche en évènements open source à Dijon:Rendez-vous cartographique (20 sept)Afpyro Computer Camp (29/20 sept)Debian bug squashing Party (29/30 sept)Si vous aimez le vin, il faut aller au #2 ;)</summary>

  <content type="text/html" mode="escaped"
           xml:space="preserve">Hasard du calendrier, le mois de septembre sera riche en évènements open source à Dijon:&lt;br&gt;&lt;a href="http://linuxfr.org/2007/09/11/23082.html"&gt;&lt;br&gt;&lt;/a&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://linuxfr.org/2007/09/11/23082.html"&gt;Rendez-vous cartographique (20 sept)&lt;br&gt;&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.afpy.org/wiki/AfpyComputerCamp"&gt;Afpyro Computer Camp (29/20 sept)&lt;br&gt;&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://linuxfr.org/2007/09/06/23070.html"&gt;Debian bug squashing Party (29/30 sept)&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br&gt;Si vous aimez le vin, il faut aller au #2 ;)&lt;br&gt;</content>

  <id>tag:programmation-python.org:sections:blog:2007_09_13_dijon-capitale-du-v</id>
  <link rel="service.edit" type="application/atom+xml"
        href="http://programmation-python.org/sections/blog/2007_09_13_dijon-capitale-du-v/atom?2007_09_13_dijon-capitale-du-v"
        title="Edit Here - Dijon capitale du V.. Libre !" />
</entry>

  
  
      <entry xmlns="http://purl.org/atom/ns#"
       xmlns:dc="http://purl.org/dc/elements/1.1/">
     
  <title mode="escaped" type="text/html">Recherche des similitudes par inférence Bayesienne</title>
  <link rel="alternate" type="text/html"
        href="http://programmation-python.org/sections/blog/2007_08_20_recherche-similitudes" />
  <issued>2007-08-20T06:48:05Z</issued>
  <modified>2007-08-20T06:48:05Z</modified>
  <created>2007-08-20T06:39:11Z</created>
  <draft xmlns="http://purl.org/atom-blog/ns#">false</draft>
  <author>
    <name>tarek</name>
  </author>
  
  
    <dc:subject>coding</dc:subject>
  
  
  <summary type="text/html" mode="escaped">Le site fr.luvdit.com permet de proposer aux visiteurs une sélection de livres grâce au k-NN, mais il part du principe que ces derniers utilisent avec pertinence les étiquettes, ce qui est loin d'être systèmatique: seuls les geeks et les personnes habituées aux sites comme flickr ou delicious le font correctement.Pour pallier à ce problème, une autre méthode de sélection peut venir renforcer ...</summary>

  <content type="text/html" mode="escaped"
           xml:space="preserve">Le site &lt;a href="http://fr.luvdit.com"&gt;fr.luvdit.com&lt;/a&gt; permet de proposer aux visiteurs une sélection de livres grâce au &lt;a href="http://programmation-python.org/sections/blog/2007_06_22_mon-voisin"&gt;k-NN&lt;/a&gt;, mais il part du principe que ces derniers utilisent avec pertinence les étiquettes, ce qui est loin d'être systèmatique: seuls les geeks et les personnes habituées aux sites comme flickr ou delicious le font correctement.&lt;br&gt;&lt;br&gt;Pour pallier à ce problème, une autre méthode de sélection peut venir renforcer celle du k-NN: &lt;a href="http://fr.wikipedia.org/wiki/Inf%C3%A9rence_bay%C3%A9sienne"&gt;l'inférence bayesienne&lt;/a&gt;. Cette technique permet d'associer à des catégories une liste de mots (==un texte). Lorsqu'une nouvelle liste de mots est rencontrée, le système calcul la probabilité d'appartenance à chacune des catégories existantes, en fonction des listes  de mots déjà croisées. Pour augmenter la pertinence, les mots communs ou courts sont supprimés, pour tenter de conserver l'essence du texte.&lt;br&gt;&lt;br&gt;Elle est appliquée ainsi au site:&lt;br&gt;&lt;ul&gt;&lt;li&gt;Le résumé (==la liste des mots) de chaque livre commenté par un utilisateur est associé à une étiquette correspondant à la note que ce dernier a donné;&lt;/li&gt;&lt;li&gt;de la même manière, le résumé est associé à chaque étiquette que l'utilisateur a donné.&lt;/li&gt;&lt;/ul&gt;&lt;br&gt;Lorsque des nouveaux livres sont ajoutés, le système va calculer pour chaque:&lt;br&gt;&lt;ul&gt;&lt;li&gt;la note que l'utilisateur pourrait donner;&lt;/li&gt;&lt;li&gt;les étiquettes qu'il pourrait mettre.&lt;/li&gt;&lt;/ul&gt;&lt;br&gt;Les propositions obtenues par le k-NN peuvent dès lors être renforcées par ce résultat:&lt;br&gt;&lt;ul&gt;&lt;li&gt;les livres à note possible élevée sont mis en avant;&lt;/li&gt;&lt;li&gt;lorsque l'utilisateur choisi des étiquettes, celles calculées par le systèmes sont proposées.&lt;/li&gt;&lt;/ul&gt;&lt;br&gt;Pour affiner les calculs, l'utilisateur pourra réfuter un livre en indiquant que ce dernier ne l'intéresse pas. Cette action aura pour effet de recalculer les probabilités des catégories. Le code-maquette est ici: &lt;a href="http://hg.programmation-python.org/browser/classifier"&gt;http://hg.programmation-python.org/browser/classifier.&lt;/a&gt; Mais est encore affreusement lent à cause d'une mauvaise conception au niveau du stockage SQL. Il est en cours de refactorisation, mais fonctionne déjà. A terme le paquet &lt;i&gt;classifier&lt;/i&gt; pourra servir à n'importe quel besoin d'inférence bayésienne (et il y en a partout). &lt;a href="http://hg.programmation-python.org/browser/classifier/doc/classifier.txt"&gt;Le doctest montre le fonctionnement&lt;/a&gt;.&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;</content>

  <id>tag:programmation-python.org:sections:blog:2007_08_20_recherche-similitudes</id>
  <link rel="service.edit" type="application/atom+xml"
        href="http://programmation-python.org/sections/blog/2007_08_20_recherche-similitudes/atom?2007_08_20_recherche-similitudes"
        title="Edit Here - Recherche des similitudes par inférence Bayesienne" />
</entry>

  
  
      <entry xmlns="http://purl.org/atom/ns#"
       xmlns:dc="http://purl.org/dc/elements/1.1/">
     
  <title mode="escaped" type="text/html">Ressources Python</title>
  <link rel="alternate" type="text/html"
        href="http://programmation-python.org/sections/blog/2007_08_13_ressources-python" />
  <issued>2007-08-14T08:35:39Z</issued>
  <modified>2007-08-14T08:35:39Z</modified>
  <created>2007-08-13T10:35:58Z</created>
  <draft xmlns="http://purl.org/atom-blog/ns#">false</draft>
  <author>
    <name>tarek</name>
  </author>
  
  
    <dc:subject>coding</dc:subject>
  
  
    <dc:subject>documentation</dc:subject>
  
  
    <dc:subject>livre</dc:subject>
  
  
  <summary type="text/html" mode="escaped">Cette page regroupe une liste de ressources web pour le langage Python, organisées en catégories. Elle démarre à peine et sera mise à jour régulièrement.Catégories:Référence du langageAide-mémoireBibliothèques tiercesFrameworks webBlogsSites webPrésentations, tutorielsRéférence du langagehttp://docs.python.org/ est le point de départ pour rechercher de la documentation en ligne sur la syntaxe de ...</summary>

  <content type="text/html" mode="escaped"
           xml:space="preserve">Cette page regroupe une liste de ressources web pour le langage Python, organisées en catégories. Elle démarre à peine et sera mise à jour régulièrement.&lt;br&gt;&lt;br&gt;Catégories:&lt;br&gt;&lt;br&gt;&lt;ul&gt;&lt;li&gt;Référence du langage&lt;br&gt;&lt;/li&gt;&lt;li&gt;Aide-mémoire&lt;/li&gt;&lt;li&gt;Bibliothèques tierces&lt;/li&gt;&lt;li&gt;Frameworks web&lt;br&gt;&lt;/li&gt;&lt;li&gt;Blogs&lt;/li&gt;&lt;li&gt;Sites web&lt;/li&gt;&lt;li&gt;Présentations, tutoriels&lt;br&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br&gt;&lt;h2&gt;Référence du langage&lt;br&gt;&lt;/h2&gt;&lt;br&gt;&lt;a href="http://docs.python.org/"&gt;http://docs.python.org/&lt;/a&gt; est le point de départ pour rechercher de la documentation en ligne sur la syntaxe de Python. Les sections les plus importantes sont:&lt;br&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://docs.python.org/lib/lib.html"&gt;La référence de la bibliothèque standard&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://docs.python.org/tut/tut.html"&gt;Un tutoriel qui parcourt les principales fonctionnalités du langage&lt;/a&gt;&lt;br&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br&gt;&lt;h2&gt;Aide-mémoire&lt;/h2&gt;&lt;br&gt;Laurent Pointal maintient une &lt;a href="http://www.limsi.fr/Individu/pointal/python/pqrc/"&gt;Quick Reference Card&lt;/a&gt; qui regroupe sur une feuille A4 une cheatsheet.&lt;br&gt;&amp;nbsp;&lt;br&gt;&lt;h2&gt;Bibliothèques tierces&lt;/h2&gt;&lt;br&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.sqlalchemy.org/"&gt;SQLAlchemy&lt;/a&gt;, &lt;a href="http://fr.wikipedia.org/wiki/Object-relational_mapping"&gt;ORM&lt;/a&gt; le plus utilisé&lt;br&gt; &lt;/li&gt;&lt;/ul&gt;&lt;br&gt;&lt;br&gt;&lt;h2&gt;Frameworks web&lt;/h2&gt;&lt;br&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.djangoproject.com/"&gt;Django&lt;/a&gt;&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Extensions&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Extension &lt;a href="http://code.google.com/p/django-openid/"&gt;django-openid&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;Extension &lt;a href="http://code.google.com/p/django-voting/"&gt;django-voting&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;Plus d'extensions via &lt;a href="http://www.google.com/search?q=django-+-:inurl:/source+-inurl:/wiki+-inurl:/soc&amp;amp;hl=en&amp;amp;domains=code.google.com&amp;amp;sitesearch=code.google.com&amp;amp;start=0&amp;amp;sa=N"&gt;une recherche google&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;Environnement de développement pour Windows: &lt;a href="http://www.instantdjango.com/"&gt;Instant Django&lt;/a&gt;&lt;br&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;&lt;a href="http://pylonshq.com/"&gt;Pylons&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://zope.org"&gt;Zope&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://turbogears.org/"&gt;TurboGears&lt;/a&gt;&lt;br&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br&gt;&lt;br&gt;Comparatifs en français : &lt;a href="http://www.biologeek.com/journal/index.php/comparaison-de-turbogears-et-django-deux-frameworks-web-python"&gt;Django vs Turbogears&lt;/a&gt;&lt;br&gt;&lt;br&gt;&lt;h2&gt;Blogs&lt;/h2&gt;&lt;br&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.biologeek.com/journal/"&gt;Biologeek&lt;/a&gt;, orienté Django&lt;/li&gt;&lt;li&gt;&lt;a href="http://kib2.webfactional.com/"&gt;Kib's blog&lt;/a&gt;, LaTeX, Django et reSTructuredText&lt;/li&gt;&lt;li&gt;&lt;a href="http://jehaisleprintemps.net/"&gt;Je Hais le Printemps&lt;/a&gt;, Django, Ubuntu&lt;br&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br&gt;-&amp;gt; si vous avez un blog, n'hésitez pas à le signaler en commentant&lt;br&gt;&lt;br&gt;&lt;h2&gt;Sites web&lt;/h2&gt;&lt;br&gt;&lt;ul&gt;&lt;li&gt;Le site de l'Afpy (Asssociation Francophone Python) : &lt;a href="http://afpy.org"&gt;http://afpy.org&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.learningpython.com/"&gt;LearningPython&lt;/a&gt;, tutoriel simples et efficaces en anglais&lt;/li&gt;&lt;li&gt;Dive Into Python, &lt;a href="http://diveintopython.org/"&gt;version anglaise&lt;/a&gt;, &lt;a href="http://diveintopython.adrahon.org/"&gt;version française&lt;/a&gt;&lt;br&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br&gt;&lt;br&gt;&lt;h2&gt;Présentations, tutoriels&lt;/h2&gt;&lt;br&gt;&lt;ul&gt;&lt;li&gt;Django à Oscon: &lt;a href="http://toys.jacobian.org/presentations/2007/oscon/tutorial/"&gt;http://toys.jacobian.org/presentations/2007/oscon/tutorial/&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br&gt;N'hésitez pas à commenter ce billet pour le compléter&lt;br&gt;&lt;br&gt;</content>

  <id>tag:programmation-python.org:sections:blog:2007_08_13_ressources-python</id>
  <link rel="service.edit" type="application/atom+xml"
        href="http://programmation-python.org/sections/blog/2007_08_13_ressources-python/atom?2007_08_13_ressources-python"
        title="Edit Here - Ressources Python" />
</entry>

  
  
      <entry xmlns="http://purl.org/atom/ns#"
       xmlns:dc="http://purl.org/dc/elements/1.1/">
     
  <title mode="escaped" type="text/html">Un widget flash pour luvdit!</title>
  <link rel="alternate" type="text/html"
        href="http://programmation-python.org/sections/blog/2007_08_10_widget-flash-pour-luvdit" />
  <issued>2007-08-10T13:14:13Z</issued>
  <modified>2007-08-10T13:14:13Z</modified>
  <created>2007-08-10T13:08:02Z</created>
  <draft xmlns="http://purl.org/atom-blog/ns#">false</draft>
  <author>
    <name>tarek</name>
  </author>
  
  
    <dc:subject>coding</dc:subject>
  
  
  <summary type="text/html" mode="escaped">Julien m'a fait un petit widget flash pour ludvit!. Le code récupère un flux xml sur le site, qui permet de lister les 5 derniers items commentés ou ajoutés par un utilisateur donné. Il apparaît sur mon blog à gauche.Voici le code à inclure:
&amp;lt;object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000"         ...</summary>

  <content type="text/html" mode="escaped"
           xml:space="preserve">&lt;a href="http://fantomas.jjteam.info"&gt;Julien&lt;/a&gt; m'a fait un petit widget flash pour &lt;a href="http://fr.luvdit.com"&gt;ludvit!&lt;/a&gt;. Le code récupère un flux xml sur le site, qui permet de lister les 5 derniers items commentés ou ajoutés par un utilisateur donné. Il apparaît sur mon blog à gauche.&lt;br&gt;&lt;br&gt;Voici le code à inclure:&lt;br&gt;
&lt;pre&gt;&amp;lt;object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" &lt;br&gt;        codebase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=8,0,0,0" &lt;br&gt;        width="80" height="450" id="widget" align="middle"&amp;gt;&lt;br&gt; &amp;lt;param name="allowScriptAccess" value="sameDomain" /&amp;gt; &lt;br&gt; &amp;lt;param name="FlashVars" value="user=tarek"&amp;gt;&lt;br&gt; &amp;lt;param name="wmode" value="transparent" /&amp;gt;&lt;br&gt; &amp;lt;param name="movie" value="http://fr.luvdit.com/js/widget.swf" /&amp;gt;&lt;br&gt; &amp;lt;param name="loop" value="false" /&amp;gt;&lt;br&gt; &amp;lt;param name="menu" value="false" /&amp;gt;&lt;br&gt; &amp;lt;param name="quality" value="high" /&amp;gt;&lt;br&gt; &amp;lt;param name="bgcolor" value="#ffffff" /&amp;gt;&lt;br&gt; &amp;lt;embed src="http://fr.luvdit.com/js/widget.swf" &lt;br&gt;        FlashVars="user=tarek" loop="false" menu="false" &lt;br&gt;        quality="high" bgcolor="#ffffff" width="80" &lt;br&gt;        height="450" name="widget" align="middle" &lt;br&gt;        allowScriptAccess="sameDomain" &lt;br&gt;        wmode="transparent"&lt;br&gt;        type="application/x-shockwave-flash" &lt;br&gt;        pluginspage="http://www.macromedia.com/go/getflashplayer" /&amp;gt;&lt;br&gt;&amp;lt;br/&amp;gt;&lt;br&gt;&amp;lt;a href="http://fr.luvdit.com"&amp;gt;luvdit!&amp;lt;/a&amp;gt;&lt;br&gt;&lt;/pre&gt;

Si vous avez un compte sur le site, il suffit de remplacer 'tarek' par votre login dans les paramètres du widget.&lt;br&gt;</content>

  <id>tag:programmation-python.org:sections:blog:2007_08_10_widget-flash-pour-luvdit</id>
  <link rel="service.edit" type="application/atom+xml"
        href="http://programmation-python.org/sections/blog/2007_08_10_widget-flash-pour-luvdit/atom?2007_08_10_widget-flash-pour-luvdit"
        title="Edit Here - Un widget flash pour luvdit!" />
</entry>

  
  
      <entry xmlns="http://purl.org/atom/ns#"
       xmlns:dc="http://purl.org/dc/elements/1.1/">
     
  <title mode="escaped" type="text/html">Au coeur de Python Volume 1</title>
  <link rel="alternate" type="text/html"
        href="http://programmation-python.org/sections/blog/2007_07_30_au-coeur-python-volume-1" />
  <issued>2007-07-30T13:44:06Z</issued>
  <modified>2007-07-30T13:44:06Z</modified>
  <created>2007-07-30T13:44:05Z</created>
  <draft xmlns="http://purl.org/atom-blog/ns#">false</draft>
  <author>
    <name>tarek</name>
  </author>
  
  
    <dc:subject>documentation</dc:subject>
  
  
  <summary type="text/html" mode="escaped">J'ai reçu la traduction de l'ouvrage de Wesley Chun, "Core Python Programming". La version française se présente en deux tomes, dont voici le premier:Au coeur de Python, Tome 1, Notions fondamentalesSi vous l'avez lu, n'hésitez pas à commenter la fiche</summary>

  <content type="text/html" mode="escaped"
           xml:space="preserve">J'ai reçu la traduction de l'ouvrage de Wesley Chun, "Core Python Programming". La version française se présente en deux tomes, dont voici le premier:&lt;br&gt;&lt;a href="http://fr.luvdit.com/items/17/"&gt;&lt;br&gt;Au coeur de Python, Tome 1, Notions fondamentales&lt;/a&gt;&lt;br&gt;&lt;br&gt;Si vous l'avez lu, n'hésitez pas à commenter la fiche&lt;br&gt;</content>

  <id>tag:programmation-python.org:sections:blog:2007_07_30_au-coeur-python-volume-1</id>
  <link rel="service.edit" type="application/atom+xml"
        href="http://programmation-python.org/sections/blog/2007_07_30_au-coeur-python-volume-1/atom?2007_07_30_au-coeur-python-volume-1"
        title="Edit Here - Au coeur de Python Volume 1" />
</entry>

  
  
      <entry xmlns="http://purl.org/atom/ns#"
       xmlns:dc="http://purl.org/dc/elements/1.1/">
     
  <title mode="escaped" type="text/html">Un site de critiques de livre</title>
  <link rel="alternate" type="text/html"
        href="http://programmation-python.org/sections/blog/2007_07_22_site-critiques-livre" />
  <issued>2007-08-09T08:21:44Z</issued>
  <modified>2007-08-09T08:21:44Z</modified>
  <created>2007-07-22T11:20:58Z</created>
  <draft xmlns="http://purl.org/atom-blog/ns#">false</draft>
  <author>
    <name>tarek</name>
  </author>
  
  
    <dc:subject>coding</dc:subject>
  
  
    <dc:subject>django</dc:subject>
  
  
    <dc:subject>documentation</dc:subject>
  
  
    <dc:subject>litterature</dc:subject>
  
  
    <dc:subject>livre</dc:subject>
  
  
  <summary type="text/html" mode="escaped">J'ai commencé à regrouper sur un site toutes mes lectures. L'application qui fait fonctionner ce site reprend tous les principes énoncés dans les billets suivants:Service de mailing asynchroneQui est mon voisin ?Cache local pour des ressources tiercesServeur d'indexation XapianIndexation facile avec XapianUn widget en flash permet aussi d'afficher sur un blog (regardez à gauche) ses 5 dernières ...</summary>

  <content type="text/html" mode="escaped"
           xml:space="preserve">J'ai commencé à regrouper sur un &lt;a href="http://fr.luvdit.com"&gt;site&lt;/a&gt; toutes mes lectures. L'application qui fait fonctionner ce site reprend tous les principes énoncés dans les billets suivants:&lt;br&gt;&lt;br&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://programmation-python.org/sections/blog/2007_07_05_service-mailing"&gt;Service de mailing asynchrone&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://programmation-python.org/sections/blog/2007_06_22_mon-voisin"&gt;Qui est mon voisin ?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://programmation-python.org/sections/blog/2007_06_18_cache-local-pour"&gt;Cache local pour des ressources tierces&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://programmation-python.org/sections/blog/2007_06_12_serveur-d-indexation"&gt;Serveur d'indexation Xapian&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://programmation-python.org/sections/blog/2007_06_07_indexation-facile-rapide"&gt;Indexation facile avec Xapian&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br&gt;Un widget en flash permet aussi d'afficher sur un blog (regardez à gauche) ses 5 dernières critiques (merci Julien).&lt;br&gt;&lt;br&gt;Et c'est &lt;a href="http://www.djangoproject.com/"&gt;Django&lt;/a&gt; Powered. Si vous aimez bien lire et partager, rejoignez moi sur &lt;a href="http://fr.luvdit.com"&gt;fr.luvdit.com&lt;/a&gt;, même s'il n'est pas tout à fait terminé, il est déjà utilisable.&lt;br&gt;</content>

  <id>tag:programmation-python.org:sections:blog:2007_07_22_site-critiques-livre</id>
  <link rel="service.edit" type="application/atom+xml"
        href="http://programmation-python.org/sections/blog/2007_07_22_site-critiques-livre/atom?2007_07_22_site-critiques-livre"
        title="Edit Here - Un site de critiques de livre" />
</entry>

  
  
      <entry xmlns="http://purl.org/atom/ns#"
       xmlns:dc="http://purl.org/dc/elements/1.1/">
     
  <title mode="escaped" type="text/html">Un joli trac pour mes projets</title>
  <link rel="alternate" type="text/html"
        href="http://programmation-python.org/sections/blog/2007_07_06_joli-trac-pour-mes" />
  <issued>2007-07-06T11:19:08Z</issued>
  <modified>2007-07-06T11:19:08Z</modified>
  <created>2007-07-06T11:19:08Z</created>
  <draft xmlns="http://purl.org/atom-blog/ns#">false</draft>
  <author>
    <name>tarek</name>
  </author>
  
  
    <dc:subject>misc</dc:subject>
  
  
  <summary type="text/html" mode="escaped">J'ai insallé un trac pour mes projets, avec le plugin Mercurial.http://hg.programmation-python.org/L'interface est beaucoup pus agréable que le browser web par défaut de Mercurial.Joie.</summary>

  <content type="text/html" mode="escaped"
           xml:space="preserve">J'ai insallé un trac pour mes projets, avec &lt;a href="http://trac.edgewall.org/wiki/TracMercurial"&gt;le plugin Mercurial&lt;/a&gt;.&lt;br&gt;&lt;br&gt;&lt;a href="http://hg.programmation-python.org/"&gt;http://hg.programmation-python.org/&lt;/a&gt;&lt;br&gt;&lt;br&gt;L'interface est beaucoup pus agréable que le browser web par défaut de Mercurial.&lt;br&gt;&lt;br&gt;Joie.&lt;br&gt;</content>

  <id>tag:programmation-python.org:sections:blog:2007_07_06_joli-trac-pour-mes</id>
  <link rel="service.edit" type="application/atom+xml"
        href="http://programmation-python.org/sections/blog/2007_07_06_joli-trac-pour-mes/atom?2007_07_06_joli-trac-pour-mes"
        title="Edit Here - Un joli trac pour mes projets" />
</entry>

  
  
      <entry xmlns="http://purl.org/atom/ns#"
       xmlns:dc="http://purl.org/dc/elements/1.1/">
     
  <title mode="escaped" type="text/html">Service de mailing asynchrone pour Django, Plone, etc..</title>
  <link rel="alternate" type="text/html"
        href="http://programmation-python.org/sections/blog/2007_07_05_service-mailing" />
  <issued>2007-07-05T21:01:38Z</issued>
  <modified>2007-07-05T21:01:38Z</modified>
  <created>2007-07-05T20:34:24Z</created>
  <draft xmlns="http://purl.org/atom-blog/ns#">false</draft>
  <author>
    <name>tarek</name>
  </author>
  
  
    <dc:subject>coding</dc:subject>
  
  
    <dc:subject>django</dc:subject>
  
  
    <dc:subject>zope</dc:subject>
  
  
  <summary type="text/html" mode="escaped">Django ne déroge pas à la règle, et fourni dans comme pour la plupart des frameworks web Python, un module pour l'envoi de mail totalement... inutilisable dans des conditions de production. En effet, send_mail et send_mass_mail, les deux API de django.core.mail, envoient tous les deux les mails de manière synchrone. L'effet est relativement désastreux sur les performances du site puisque chaque ...</summary>

  <content type="text/html" mode="escaped"
           xml:space="preserve">Django ne déroge pas à la règle, et fourni dans comme pour la plupart des frameworks web Python, un module pour l'envoi de mail totalement... inutilisable dans des conditions de production. En effet, &lt;i&gt;send_mail&lt;/i&gt; et &lt;i&gt;send_mass_mail&lt;/i&gt;, les deux API de &lt;a href="http://code.djangoproject.org/browser/django/trunk/django/core/mail.py"&gt;&lt;i&gt;django.core.mail&lt;/i&gt;&lt;/a&gt;, envoient tous les deux les mails de manière synchrone. &lt;br&gt;&lt;br&gt;L'effet est relativement désastreux sur les performances du site puisque chaque envoi de mail provoque un blocage du thread en cours, le temps de l'échange avec le serveur SMTP via telnet. Sur un site chargé, ou qui utilise de façon massive les envois de mails, l'emploi de &lt;i&gt;django.core.mail&lt;/i&gt; est donc fortement déconseillé.&lt;br&gt;&lt;br&gt;Plus globalement, tout code qui n'entre pas en ligne de compte pour calculer la page à afficher, ne doit pas s'exécuter de manière synchrone (autres exemples de calculs asynchrones: &lt;a href="http://programmation-python.org/sections/blog/2007_06_22_mon-voisin"&gt;calculs des voisins&lt;/a&gt;, &lt;a href="http://programmation-python.org/sections/blog/2007_06_12_serveur-d-indexation"&gt;indexation&lt;/a&gt;, etc).&lt;br&gt;&lt;br&gt;Zope 3, un peu plus mature et sophistiqué que les autres frameworks sur ce point précis, propose un module d'envoi de mails asynchrone, qui recopie les mails dans un répertoire au format &lt;a href="http://en.wikipedia.org/wiki/Maildir"&gt;&lt;i&gt;Maildir&lt;/i&gt;,&lt;/a&gt; et lance un thread en charge de dépiler les mails du répertoire. L'interêt, outre l'aspect asynchrone qui permet d'accélerer les envois et de libérer le thread qui sert la page immédiatement, est la robustesse: si le serveur tombe, le thread peut reprendre son travail d'envoi lorsqu'il est relancé.&lt;br&gt;&lt;br&gt;Mais cette solution reste liée au serveur d'application car le thread est lié au processus. L'autre défaut est qu'il est nécessaire, si l'on veut ajouter des informations supplémentaires aux mails à traiter, d'ajouter des en-têtes pour respecter le format &lt;a href="http://www.faqs.org/rfcs/rfc2822.html"&gt;RFC-2822&lt;/a&gt; des mails qui sont recopiés dans la maildir (et de les retirer avant l'envoi réel des mails). Enfin, le code devient dépendant du système de fichiers, ce qui peut poser des problèmes d'infrastructure si l'on déploie ce service d'envoi de mails sur une machine tierce au serveur d'application.&lt;br&gt;&lt;br&gt;Une autre solution, beaucoup plus robuste, consiste à déposer ces mails dans une table de base de donnée relationnelle (celle employée par le site dans Django, ou une dédiée pour Zope) qui est lue régulièrement par un service d'envois de mails, totalement indépendant du serveur web.&lt;br&gt;&lt;br&gt;&lt;h3&gt;Deux tables pour le prix d'une&lt;/h3&gt;&lt;br&gt;Pour mettre en place ce service, deux tables sont créées dans la base de données, grâce à SQLAlchemy:&lt;br&gt;
&lt;pre&gt;mail_data = Table('mailer_mail_data', metadata,&lt;br&gt;                   Column('id', Integer, primary_key=True, autoincrement=True),&lt;br&gt;                   Column('subject', String(300)),&lt;br&gt;                   Column('sender', String(300)),&lt;br&gt;                   Column('recipients', String(300)),&lt;br&gt;                   Column('date', DateTime()),&lt;br&gt;                   Column('data', TEXT()))&lt;br&gt;&lt;br&gt;mailed_data = Table('mailer_mailed_data', metadata,&lt;br&gt;                   Column('id', Integer, primary_key=True, autoincrement=True),&lt;br&gt;                   Column('subject', String(300)),&lt;br&gt;                   Column('sender', String(300)),&lt;br&gt;                   Column('original_id', Integer),&lt;br&gt;                   Column('recipients', String(300)),&lt;br&gt;                   Column('error', String(300)),&lt;br&gt;                   Column('data', TEXT()),&lt;br&gt;                   Column('date', DateTime()),&lt;br&gt;                   Column('status', String(10)),)&lt;br&gt;&lt;/pre&gt;

La table &lt;i&gt;mail_data&lt;/i&gt; sert à stocker les informations sur les mails à envoyer, et la table &lt;i&gt;mailed_data&lt;/i&gt; permet de stocker les mails envoyés, avec pour chaque un statut, si jamais l'envoi a échoué. Cette deuxième table permet aux applications de mettre en place du feedback en cas de problème d'envoi.&lt;br&gt;&lt;br&gt;&lt;h3&gt;Travailleuse, travailleur&lt;/h3&gt;&lt;br&gt;Le programme en charge d'envoyer les mails est un thread qui ouvre régulièrement la base pour:&lt;br&gt;&lt;ul&gt;&lt;li&gt;Lire la table &lt;i&gt;mail_data&lt;/i&gt; et envoyer les mails qu'elle contient&lt;/li&gt;&lt;li&gt;Archiver les mails envoyés, avec ou sans erreurs, dans &lt;i&gt;mailed_data&lt;/i&gt;&lt;/li&gt;&lt;li&gt;Supprimer les mails envoyés de la table &lt;i&gt;mail_data&lt;/i&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br&gt;Il est lancé comme programme indépendant vi un script &lt;i&gt;run.py&lt;/i&gt;, qui peut être dameonisé sur le serveur grâce aux &lt;a href="http://cr.yp.to/daemontools.html"&gt;dameontools&lt;/a&gt; par exemple (il y a surement plus simple de nos jours avis aux experts Linux...)&lt;br&gt;
&lt;pre&gt;class MailWorker(Thread):&lt;br&gt;    """reads the SQLDB to do the jobs"""&lt;br&gt;&lt;br&gt;    def __init__(self):&lt;br&gt;        Thread.__init__(self)&lt;br&gt;        self.is_working = False&lt;br&gt;        self.running = False&lt;br&gt;&lt;br&gt;    def _get_mails(self):&lt;br&gt;        """returns lines of mail_data """&lt;br&gt;        return mail_data.select().execute().fetchall()&lt;br&gt;&lt;br&gt;    def _get_message(self, mail):&lt;br&gt;        """returns a Mime"""&lt;br&gt;        msg = MIMEText(b64decode(mail.data))&lt;br&gt;        msg['From'] = mail.sender&lt;br&gt;        msg['To'] = mail.recipients&lt;br&gt;        msg['Subject'] = mail.subject&lt;br&gt;&lt;br&gt;        msg['Date'] = mail.date.isoformat()&lt;br&gt;        return msg&lt;br&gt;&lt;br&gt;    def _send_mail(self, mail):&lt;br&gt;        """sends the mail"""&lt;br&gt;        server = smtplib.SMTP(settings.SMTP_SERVER)&lt;br&gt;        msg = self._get_message(mail)&lt;br&gt;        try:&lt;br&gt;            server.sendmail(msg['From'], msg['To'], msg.as_string())&lt;br&gt;        finally:&lt;br&gt;            server.quit()&lt;br&gt;        logging.debug('mailer:message sent to %s' % msg['To'])&lt;br&gt;&lt;br&gt;    def _store_mail(self, mail, error=None):&lt;br&gt;        """stores the mail"""&lt;br&gt;        if error is not None:&lt;br&gt;            error = str(error)&lt;br&gt;        ins = mailed_data.insert()&lt;br&gt;        ins.execute(subject=mail.subject, sender=mail.sender,&lt;br&gt;                    original_id=mail.id, recipients=mail.recipients,&lt;br&gt;                    error=error, data=mail.data, date=datetime.now(),&lt;br&gt;                    status='processed')&lt;br&gt;&lt;br&gt;        # removes from original table&lt;br&gt;        mail_data.delete().execute(id=mail.id)&lt;br&gt;&lt;br&gt;    def run(self):&lt;br&gt;        """called threaded"""&lt;br&gt;        self.running = True&lt;br&gt;        logging.debug('mailer:launched')&lt;br&gt;&lt;br&gt;        while self.running:&lt;br&gt;            # index&lt;br&gt;            self.is_working = True&lt;br&gt;            try:&lt;br&gt;                # get mails to send&lt;br&gt;                mails = self._get_mails()&lt;br&gt;                for mail in mails:&lt;br&gt;                    try:&lt;br&gt;                        # send then&lt;br&gt;                        self._send_mail(mail)&lt;br&gt;                    except Exception, e:&lt;br&gt;                        logging.debug('mailer:failed to send mail')&lt;br&gt;                        self._store_mail(mail, e)&lt;br&gt;                    else:&lt;br&gt;                        self._store_mail(mail)&lt;br&gt;            finally:&lt;br&gt;                self.is_working = False&lt;br&gt;                time.sleep(.1)&lt;br&gt;&lt;br&gt;        logging.debug('mailer:stopped')&lt;br&gt;&lt;br&gt;worker = None&lt;br&gt;&lt;br&gt;def start_server():&lt;br&gt;    """starts the worker"""&lt;br&gt;    global worker&lt;br&gt;    worker = MailWorker()&lt;br&gt;    worker.start()&lt;br&gt;&lt;br&gt;def stop_server():&lt;br&gt;    """stops the worker"""&lt;br&gt;    global worker&lt;br&gt;    if worker is not None:&lt;br&gt;        worker.running = False&lt;br&gt;        worker.join()&lt;br&gt;        worker = None&lt;br&gt;&lt;br&gt;def is_working():&lt;br&gt;    """tells if the worker works"""&lt;br&gt;    return worker.is_working&lt;br&gt;&lt;br&gt;# will make sure the thread stops when the process quits&lt;br&gt;from atexit import register&lt;br&gt;register(stop_server)&lt;br&gt;&lt;/pre&gt;

&lt;br&gt;&lt;h3&gt;API d'envoi de mail&lt;/h3&gt;&lt;br&gt;Enfin, les applications peuvent se servir du module &lt;i&gt;sender&lt;/i&gt; pour envoyer des mails. Ce dernier injecte dans la table &lt;i&gt;mail_data&lt;/i&gt; le mail et rend la main immédiatement&lt;br&gt;
&lt;pre&gt;def send_mail(sender, recipients, subject, msg):&lt;br&gt;    """sends the mail by storing it into the DB"""&lt;br&gt;    inserter = mail_data.insert()&lt;br&gt;    res = inserter.execute(subject=subject, sender=sender,&lt;br&gt;                          recipients=','.join(recipients),&lt;br&gt;                          data=b64encode(msg), date=datetime.now())&lt;br&gt;&lt;br&gt;    return res.last_inserted_ids()[0]&lt;br&gt;&lt;/pre&gt;
&lt;br&gt;J'utilise cette API dans mes applications pour tous les envois de mail. Dans Django, elle remplace avantageusement &lt;i&gt;django.core.mail&lt;/i&gt;.&lt;br&gt;&lt;br&gt;&lt;h3&gt;Exemple complet &lt;/h3&gt;&lt;br&gt;Voici la docstring du paquet que j'ai conçu&lt;br&gt;
&lt;pre&gt;mailer&lt;br&gt;=====&lt;br&gt;&lt;br&gt;Mailer provides:&lt;br&gt;&lt;br&gt;- a simple method to send mails (eg: store them)&lt;br&gt;- a worker that actually sends them&lt;br&gt;&lt;br&gt;Let's work on a sql data file for the tests:&lt;br&gt;&lt;br&gt;    &amp;gt;&amp;gt;&amp;gt; import settings&lt;br&gt;    &amp;gt;&amp;gt;&amp;gt; settings.DATABASE = test_db&lt;br&gt;&lt;br&gt;send mails&lt;br&gt;----------&lt;br&gt;&lt;br&gt;To send a mail, the package provides the `sender` module::&lt;br&gt;&lt;br&gt;    &amp;gt;&amp;gt;&amp;gt; from sender import send_mail&lt;br&gt;    &amp;gt;&amp;gt;&amp;gt; mail_id = send_mail(sender='tarek@ziade.org',&lt;br&gt;    ...                     recipients=['ziade.tarek@gmail.com'],&lt;br&gt;    ...                     subject='hello',&lt;br&gt;    ...                     msg='héllo')&lt;br&gt;&lt;br&gt;&lt;br&gt;The mail is then stored in the database, and the id returned is the&lt;br&gt;mail id in the DB.&lt;br&gt;&lt;br&gt;Another API will give the status of the mail in process::&lt;br&gt;&lt;br&gt;    &amp;gt;&amp;gt;&amp;gt; from sender import mail_status&lt;br&gt;    &amp;gt;&amp;gt;&amp;gt; mail_status(mail_id)&lt;br&gt;    u'processing'&lt;br&gt;&lt;br&gt;When the id is not given, the whole mailed table is returned::&lt;br&gt;&lt;br&gt;    &amp;gt;&amp;gt;&amp;gt; mail_status()&lt;br&gt;    []&lt;br&gt;&lt;br&gt;We can ask for the queue size as well::&lt;br&gt;&lt;br&gt;    &amp;gt;&amp;gt;&amp;gt; from sender import mail_queue_size&lt;br&gt;    &amp;gt;&amp;gt;&amp;gt; mail_queue_size()&lt;br&gt;    1&lt;br&gt;&lt;br&gt;sending mails, for real&lt;br&gt;-----------------------&lt;br&gt;&lt;br&gt;A worker is in charge of sending mails::&lt;br&gt;&lt;br&gt;    &amp;gt;&amp;gt;&amp;gt; from mailer import start_server, stop_server&lt;br&gt;    &amp;gt;&amp;gt;&amp;gt; start_server()&lt;br&gt;&lt;br&gt;The mail is then processed::&lt;br&gt;&lt;br&gt;    &amp;gt;&amp;gt;&amp;gt; import time&lt;br&gt;    &amp;gt;&amp;gt;&amp;gt; while mail_status(mail_id) == u'processing':&lt;br&gt;    ...     time.sleep(0.2)&lt;br&gt;    &amp;gt;&amp;gt;&amp;gt; mail_status(mail_id)&lt;br&gt;    u'processed'&lt;br&gt;&lt;br&gt;Let's stop the server::&lt;br&gt;&lt;br&gt;    &amp;gt;&amp;gt;&amp;gt; stop_server()&lt;br&gt;&lt;br&gt;And see the status::&lt;br&gt;&lt;br&gt;    &amp;gt;&amp;gt;&amp;gt; status = mail_status()&lt;br&gt;    &amp;gt;&amp;gt;&amp;gt; status[0]['subject']&lt;br&gt;    u'hello'&lt;br&gt;    &amp;gt;&amp;gt;&amp;gt; status[0]['status']&lt;br&gt;    u'processed'&lt;br&gt;&lt;br&gt;&lt;/pre&gt;
&lt;br&gt;Et, Ô joie, le code est disponible, comme d'habitude, sur &lt;a href="http://hg.programmation-python.org"&gt;http://hg.programmation-python.org&lt;/a&gt;, dans le paquet &lt;i&gt;mailer&lt;/i&gt;.&lt;br&gt;&lt;br&gt;</content>

  <id>tag:programmation-python.org:sections:blog:2007_07_05_service-mailing</id>
  <link rel="service.edit" type="application/atom+xml"
        href="http://programmation-python.org/sections/blog/2007_07_05_service-mailing/atom?2007_07_05_service-mailing"
        title="Edit Here - Service de mailing asynchrone pour Django, Plone, etc.." />
</entry>

  
  
      <entry xmlns="http://purl.org/atom/ns#"
       xmlns:dc="http://purl.org/dc/elements/1.1/">
     
  <title mode="escaped" type="text/html">Qui est mon voisin ?</title>
  <link rel="alternate" type="text/html"
        href="http://programmation-python.org/sections/blog/2007_06_22_mon-voisin" />
  <issued>2007-07-06T00:14:55Z</issued>
  <modified>2007-07-06T00:14:55Z</modified>
  <created>2007-06-22T15:10:21Z</created>
  <draft xmlns="http://purl.org/atom-blog/ns#">false</draft>
  <author>
    <name>tarek</name>
  </author>
  
  
    <dc:subject>coding</dc:subject>
  
  
  <summary type="text/html" mode="escaped">Dans un site de contenu, pour rechercher les similitudes entre deux documents basée sur les tags qui leur ont été associés, on recherche l'intersection commune. En d'autres termes, on recherche dans le corpus des documents les documents avec le plus grand nombre de tags communs.Les algorithmes de voisinage, qui sont les plus simples à mettre en oeuvre, permettent de trouver rapidement ces ...</summary>

  <content type="text/html" mode="escaped"
           xml:space="preserve">Dans un site de contenu, pour rechercher les similitudes entre deux documents basée sur les tags qui leur ont été associés, on recherche l'intersection commune. En d'autres termes, on recherche dans le corpus des documents les documents avec le plus grand nombre de tags communs.&lt;br&gt;&lt;br&gt;Les algorithmes de voisinage, qui sont les plus simples à mettre en oeuvre, permettent de trouver rapidement ces similitudes en disposant dans un espace multidimensionnel les documents.  Chaque dimension est un tag et le document se trouve dans cette dimension&lt;br&gt;à la coordonée 0 ou 1 (le document possède ce tag ou non).&lt;br&gt;&lt;br&gt;Une fois cette carte dressée, il est possible de retrouver les "voisins" d'un document, c'est-à-dire les documents les plus proche dans l'espace.&lt;br&gt;&lt;br&gt;Cet algorithme s'appel le &lt;b&gt;k-Nearest Neighbor&lt;/b&gt;, ou &lt;b&gt;k-NN&lt;/b&gt;.&lt;br&gt;&lt;br&gt;&lt;a href="http://www.amazon.fr/dp/0137903952?tag=programmation-21&amp;amp;camp=1414&amp;amp;creative=6410&amp;amp;linkCode=as1&amp;amp;creativeASIN=0137903952&amp;amp;adid=10YGA37DAGT1GYY579DY&amp;amp;"&gt;&lt;img  align="left" src="http://ec1.images-amazon.com/images/I/5194WJ11V1L._AA240_.jpg"&gt;&lt;/a&gt;Le livre de référence en matière de IA ("&lt;a href="http://www.amazon.fr/dp/0137903952?tag=programmation-21&amp;amp;camp=1414&amp;amp;creative=6410&amp;amp;linkCode=as1&amp;amp;creativeASIN=0137903952&amp;amp;adid=10YGA37DAGT1GYY579DY&amp;amp;"&gt;Artificial Intelligence: A Modern Approach&lt;/a&gt;"), propose une implémentation de cet algorthime en Python, disponible sur son &lt;a href="http://aima.eecs.berkeley.edu/code.html"&gt;site&lt;/a&gt;. &lt;br&gt;&lt;br&gt;&lt;h3&gt;Qui sont mes copains ?&lt;/h3&gt;&lt;br&gt;Les cas d'utilisations ne manquent pas pour le k-NN. Il peut par exemple être employé pour rechercher des similitudes entres utilisateurs de la même application. C'est le cas par exemple sur &lt;a href="http://www.last.fm/"&gt;Last.Fm&lt;/a&gt;, qui propose une fonctionnalité de "Voisinage" où la liste des utilisateurs les plus proches de vos choix en matière de Tags, est affichée. Cette liste de personne est susceptible d'avoir des goûts très similaires aux vôtres.&lt;br&gt;&lt;br&gt;&lt;h3&gt;Le paquet neighbors&lt;/h3&gt;&lt;br&gt;Pour une de mes applications, j'ai développé un paquet au dessus du code du livre, qui propose une api simplifié qui permet de retrouver les voisins d'un utilisateur, en fonction des tags utilisés. &lt;br&gt;&lt;br&gt;Il corrige aussi des erreurs (signalées) dans l'implémentation proposée par le livre et fourni un système de persistence en base, qui permet de découpler le travail de calcul des requêtes: une application peut requêter la base pour connaître les voisins d'un utilisateur, pendant qu'un processus se charge de les calculer et les mettre à jour régulièrement.&lt;br&gt;&lt;br&gt;Voici le docstring du paquet:

&lt;pre&gt;=======&lt;br&gt;neartag&lt;br&gt;=======&lt;br&gt;&lt;br&gt;This module implements the k-nearest neighbor algorithme (k-NN) that allows&lt;br&gt;to compute the distance between elements, given a set of value. Each value&lt;br&gt;is a dimension and the set are the coordinates of the element in the multi&lt;br&gt;dimensional space.&lt;br&gt;&lt;br&gt;For tags, the idea is to find neighbours of a given user, depending on the&lt;br&gt;tags she uses. The `NearestByTag` class is instanciated with those tags::&lt;br&gt;&lt;br&gt;    &amp;gt;&amp;gt;&amp;gt; from neartag import NearestByTag&lt;br&gt;    &amp;gt;&amp;gt;&amp;gt; tags = ["django", "python", "zen", "fun", "scary"]&lt;br&gt;    &amp;gt;&amp;gt;&amp;gt; solver = NearestByTag(tags)&lt;br&gt;&lt;br&gt;Then each user is added with her name and tag values (boolean value)::&lt;br&gt;&lt;br&gt;    &amp;gt;&amp;gt;&amp;gt; user_1 = 'user 1', ["django", "python"]&lt;br&gt;    &amp;gt;&amp;gt;&amp;gt; user_2 = 'user 2', ["zen", "fun", "scary"]&lt;br&gt;    &amp;gt;&amp;gt;&amp;gt; user_3 = 'user 3', ["django"]&lt;br&gt;    &amp;gt;&amp;gt;&amp;gt; user_4 = 'user 4', ["django", "python"]&lt;br&gt;    &amp;gt;&amp;gt;&amp;gt; for user, tags in (user_1, user_2, user_3, user_4):&lt;br&gt;    ...     solver.add_user(user, tags)&lt;br&gt;&lt;br&gt;The class then will give a sorted list of neighbours of a given user::&lt;br&gt;&lt;br&gt;    &amp;gt;&amp;gt;&amp;gt; solver.neighbours('user 1')&lt;br&gt;    [(0.16..., 'user 4'), (0.3..., 'user 3'), (1.0, 'user 2')]&lt;br&gt;    &amp;gt;&amp;gt;&amp;gt; solver.neighbours('user 2')&lt;br&gt;    [(0.83..., 'user 3'), (1.0, 'user 1'), (1.0, 'user 4')]&lt;br&gt;    &amp;gt;&amp;gt;&amp;gt; solver.neighbours('user 3')&lt;br&gt;    [(0.33..., 'user 1'), (0.33..., 'user 4'), (0.83..., 'user 2')]&lt;br&gt;    &amp;gt;&amp;gt;&amp;gt; solver.neighbours('user 4')&lt;br&gt;    [(0.16..., 'user 1'), (0.33..., 'user 3'), (1.0, 'user 2')]&lt;br&gt;&lt;br&gt;The smallest the returned value is, the closest the user is.&lt;br&gt;&lt;br&gt;`neighbours` will return at most 10 neighbours, but this size can be changed::&lt;br&gt;&lt;br&gt;    &amp;gt;&amp;gt;&amp;gt; solver.neighbours('user 1', 1)&lt;br&gt;    [(0.16..., 'user 4')]&lt;br&gt;&lt;br&gt;This class works in-memory, since the loaded values are small enough to fit.&lt;br&gt;&lt;br&gt;How to use it with an application&lt;br&gt;=================================&lt;br&gt;&lt;br&gt;Tags changes all the time in an application. The best use is to instanciate&lt;br&gt;the class over data retrieved from a database and to compute the distances,&lt;br&gt;then to save them within a dedicated table. Since the computation can take&lt;br&gt;time, a thread worker can update those distances from time to time in the&lt;br&gt;background.&lt;br&gt;&lt;/pre&gt;

Le paquet neighbors est disponible sur mon repository Mercurial:&lt;a href="http://hg.programmation-python.org/repositories/public/"&gt; http://hg.programmation-python.org/repositories/public/&lt;/a&gt; (il faut vraiment que je fasse une autre interface web que celle par défaut de Mercurial...)&lt;br&gt;&lt;br&gt;Merci à &lt;a href="http://www.dailymotion.com/video/x27vnx_dr-gumby-ia-avec-scientific-python"&gt;Olivier&lt;/a&gt; pour ses précieux conseils en IA !&lt;br&gt;&lt;br&gt;&lt;br&gt;</content>

  <id>tag:programmation-python.org:sections:blog:2007_06_22_mon-voisin</id>
  <link rel="service.edit" type="application/atom+xml"
        href="http://programmation-python.org/sections/blog/2007_06_22_mon-voisin/atom?2007_06_22_mon-voisin"
        title="Edit Here - Qui est mon voisin ?" />
</entry>

  
  
      <entry xmlns="http://purl.org/atom/ns#"
       xmlns:dc="http://purl.org/dc/elements/1.1/">
     
  <title mode="escaped" type="text/html">Améliorer la recherche sur un site de contenu</title>
  <link rel="alternate" type="text/html"
        href="http://programmation-python.org/sections/blog/2007_06_19_technique-simple-pour" />
  <issued>2007-06-19T10:26:46Z</issued>
  <modified>2007-06-19T10:26:46Z</modified>
  <created>2007-06-19T10:23:43Z</created>
  <draft xmlns="http://purl.org/atom-blog/ns#">false</draft>
  <author>
    <name>tarek</name>
  </author>
  
  
    <dc:subject>coding</dc:subject>
  
  
  <summary type="text/html" mode="escaped">Il y a beaucoup de sites web qui me frustrent : une recherche avec un mot donné ne fonctionne pas alors que je sais qu'il existe sur le site en question des documents correspondants. La technique la plus simple pour essayer de maximiser les résultats de recherche est d'ajouter un maximum de métadonnées sur les documents, ou d'ajouter une mécanique de synonymes dans le moteur de recherche. Mais ce ...</summary>

  <content type="text/html" mode="escaped"
           xml:space="preserve">Il y a beaucoup de sites web qui me frustrent : une recherche avec un mot donné ne fonctionne pas alors que je sais qu'il existe sur le site en question des documents correspondants. &lt;br&gt;&lt;br&gt;La technique la plus simple pour essayer de maximiser les résultats de recherche est d'ajouter un maximum de métadonnées sur les documents, ou d'ajouter une mécanique de synonymes dans le moteur de recherche. Mais ce travail est fastidieux.&lt;br&gt;&lt;br&gt;Pour faciliter ce travail, j'utilise maintenant une table qui stocke l'intégralité des recherches qui ne donnent aucun résultat, avec pour chacune le nombre de demandes.&lt;br&gt;&lt;br&gt;Cette table permet de déceler les informations que les utilisateurs tente le plus souvent de trouver sur le site sans succès. La mise en place des métadonnées devient enfantine, et lorsqu'aucun document ne peut correspondre, une attente de contenu est décelée.&lt;br&gt;&lt;br&gt;Idée simple, pas nouvelle, mais rudement efficace :)&lt;br&gt;&lt;br&gt;Et vous, connaissez vous des techniques pour améliorer l'indexation d'un site ? &lt;br&gt;&lt;br&gt;</content>

  <id>tag:programmation-python.org:sections:blog:2007_06_19_technique-simple-pour</id>
  <link rel="service.edit" type="application/atom+xml"
        href="http://programmation-python.org/sections/blog/2007_06_19_technique-simple-pour/atom?2007_06_19_technique-simple-pour"
        title="Edit Here - Améliorer la recherche sur un site de contenu" />
</entry>

  
  
      <entry xmlns="http://purl.org/atom/ns#"
       xmlns:dc="http://purl.org/dc/elements/1.1/">
     
  <title mode="escaped" type="text/html">Cache local pour des ressources tierces avec Memcached pour un site Django</title>
  <link rel="alternate" type="text/html"
        href="http://programmation-python.org/sections/blog/2007_06_18_cache-local-pour" />
  <issued>2007-06-19T09:45:47Z</issued>
  <modified>2007-06-19T09:45:47Z</modified>
  <created>2007-06-18T15:14:41Z</created>
  <draft xmlns="http://purl.org/atom-blog/ns#">false</draft>
  <author>
    <name>tarek</name>
  </author>
  
  
    <dc:subject>coding</dc:subject>
  
  
    <dc:subject>django</dc:subject>
  
  
  <summary type="text/html" mode="escaped">Lorsqu'un site web a besoin d'afficher du contenu récupéré sur un autre site, il rend la rapidité d'affichage dépendante des performances du site tiers. Pour résoudre le problème, la solution la plus simple consiste à rapatrier les ressources pour ne plus avoir à appeler le site tiers, et à les mettre à jour régulièrement.La mise en place de cette mécanique peut devenir un développement à part ...</summary>

  <content type="text/html" mode="escaped"
           xml:space="preserve">Lorsqu'un site web a besoin d'afficher du contenu récupéré sur un autre site, il rend la rapidité d'affichage dépendante des performances du site tiers. Pour résoudre le problème, la solution la plus simple consiste à rapatrier les ressources pour ne plus avoir à appeler le site tiers, et à les mettre à jour régulièrement.&lt;br&gt;&lt;br&gt;La mise en place de cette mécanique peut devenir un développement à part entière si l'on souhaite utiliser les ressources depuis plusieurs applications web ou dans une infrastucture redondante pour les montées en charge. &lt;br&gt;&lt;br&gt;Heureusement il y a &lt;strike&gt;Findus&lt;/strike&gt; &lt;a href="http://danga.com/memcached/"&gt;Memcached&lt;/a&gt;. Ce serveur de cache distribué réduit à quelques lignes le code nécessaire pour fournir à une application Python un système de cache ultra performant. Le framework Django, ansi que de nombeux produits Plone, utilisent d'ors et déjà memcached pour la mise en cache des pages web.&lt;br&gt;&lt;br&gt;Pour mettre en cache des pages web externes ou des images, le petit module ci-dessous suffit:&lt;br&gt;
&lt;pre&gt;import memcache&lt;br&gt;from urllib2 import urlopen&lt;br&gt;&lt;br&gt;host = 'localhost:11211'&lt;br&gt;&lt;br&gt;mc = memcache.Client([host], debug=0)&lt;br&gt;connected = mc.servers[0].connect() != 0&lt;br&gt;if not connected:&lt;br&gt;    raise Exception('%s seems down' % host)&lt;br&gt;&lt;br&gt;def _get_metadata(url):&lt;br&gt;    """get url infos"""&lt;br&gt;    return urlopen(url).info()&lt;br&gt;&lt;br&gt;def _get_content(url):&lt;br&gt;    """get url content"""&lt;br&gt;    return urlopen(url).read()&lt;br&gt;&lt;br&gt;def get_content(url, control=False):&lt;br&gt;    """get cached content"""&lt;br&gt;    cached = mc.get(url)&lt;br&gt;    if cached is not None:&lt;br&gt;        infos, cached = cached&lt;br&gt;        # controls the metadata to see&lt;br&gt;        # if the source has changed&lt;br&gt;        if control:&lt;br&gt;            latest_infos = _get_metadata(url)&lt;br&gt;            if latest_infos.values() == infos.values():&lt;br&gt;                return infos, cached&lt;br&gt;        else:&lt;br&gt;            return infos, cached&lt;br&gt;    cached = _get_content(url)&lt;br&gt;    infos = _get_metadata(url)&lt;br&gt;    mc.set(url, (infos, cached))&lt;br&gt;    return infos, cached&lt;br&gt;&lt;/pre&gt;
Il peut ensuite être utilisé pour l'affichage par le serveur d'application via une de ces solutions:&lt;br&gt;&lt;ul&gt;&lt;li&gt;Un proxy local appelé via une rewrite rule d'Apache qui repère les éléments externes au domaine par expression régulière. (solution la plus élégante)&lt;/li&gt;&lt;li&gt;Des urls spécifiques qui appelent une fonction en charge de renvoyer la ressource&lt;/li&gt;&lt;/ul&gt;&lt;br&gt;Dans Django, avec la solution n°2, une nouvelle expression dans &lt;i&gt;urls.py&lt;/i&gt; et une vue spécialisée, en charge de renvoyer la ressource, peuvent être utilisées. Attention cependant à conserver des urls fixes, uniques (REST quoi ;)) pour chaque image, pour ne pas perdre le cache du navigateur coté client.&lt;br&gt;&amp;nbsp;&lt;br&gt;Voici un exemple d'utilisation via Django.&lt;br&gt;&lt;br&gt;Dans urls.py l'expression régulière suivante :&lt;br&gt;

&lt;pre&gt;(r'^ext/(?P&amp;lt;url&amp;gt;.*)$', 'views.get_external')&lt;br&gt;&lt;/pre&gt;
 permet d'intercepter les urls qui commencent par &lt;i&gt;/ext&lt;/i&gt; sur le portail. En remplacant les urls des ressources externes par des urls internes et en retirant le &lt;i&gt;http://&lt;/i&gt;, on obtient des urls uniques:&lt;br&gt;

&lt;pre&gt;http://example.com/media/image1.jpg&lt;/pre&gt; 

devient 

&lt;pre&gt;/ext/example.com/media/image1.jpg&lt;/pre&gt; 

La vue invoquée peut alors appeler le module de cache:&lt;br&gt;
&lt;pre&gt;def get_external(request, url):                                                 &lt;br&gt;    """retrieves external url""" &lt;br&gt;    infos, content = cached_url.get_content('http://%s' % url)                  &lt;br&gt;    response = HttpResponse(content)&lt;br&gt;                                                                                &lt;br&gt;    del response.headers['Content-Type']                                        &lt;br&gt;&lt;br&gt;    hop_by_hop = ('connection', 'keep-alive', 'proxy-authenticate',             &lt;br&gt;                  'proxy-authorization', 'te', 'trailers',&lt;br&gt;                  'transfer-encoding', 'upgrade')                               &lt;br&gt;  &lt;br&gt;    for key in infos.keys():&lt;br&gt;        if key in hop_by_hop:&lt;br&gt;            continue&lt;br&gt;        response.headers[key] = infos[key]&lt;br&gt; &lt;br&gt;    # XXX cache info need more infos                                            &lt;br&gt;    response.headers['via2'] = 'Django memcached App'                           &lt;br&gt;                                                                                &lt;br&gt;    return response&lt;br&gt;&lt;/pre&gt;
Ce qui n'a pas été couvert dans ce billet:&lt;br&gt;&lt;ul&gt;&lt;li&gt;Le flush&lt;/li&gt;&lt;li&gt;La gestion fine des timeout du cache, avec le header Age&lt;/li&gt;&lt;/ul&gt;&lt;br&gt;Il existe d'autres solutions, via des extensions pour Apache, pour mettre en place ce fonctionnement. Mais la simplicité et la rapidité de mise en oeuvre de Memcached est telle qu'il ne faudrait pas s'en priver ;). De plus, si ce sont des images que vous récupérez, vous pouvez imaginer toute sorte de traitement avec &lt;a href="http://www.pythonware.com/products/pil/"&gt;PIL&lt;/a&gt; avant de les ranger dans le cache, ou même créer un système de thumbnails très performant.&lt;br&gt;&lt;br&gt;&lt;br&gt;</content>

  <id>tag:programmation-python.org:sections:blog:2007_06_18_cache-local-pour</id>
  <link rel="service.edit" type="application/atom+xml"
        href="http://programmation-python.org/sections/blog/2007_06_18_cache-local-pour/atom?2007_06_18_cache-local-pour"
        title="Edit Here - Cache local pour des ressources tierces avec Memcached pour un site Django" />
</entry>

  
  
      <entry xmlns="http://purl.org/atom/ns#"
       xmlns:dc="http://purl.org/dc/elements/1.1/">
     
  <title mode="escaped" type="text/html">Serveur d'indexation pour Django avec Xapian</title>
  <link rel="alternate" type="text/html"
        href="http://programmation-python.org/sections/blog/2007_06_12_serveur-d-indexation" />
  <issued>2007-06-12T14:53:27Z</issued>
  <modified>2007-06-12T14:53:27Z</modified>
  <created>2007-06-12T14:31:29Z</created>
  <draft xmlns="http://purl.org/atom-blog/ns#">false</draft>
  <author>
    <name>tarek</name>
  </author>
  
  
    <dc:subject>coding</dc:subject>
  
  
    <dc:subject>django</dc:subject>
  
  
  <summary type="text/html" mode="escaped">Dans mon post précédent, je parlais de l'indexation avec Xapian. Le fonctionnement du paquet a du être revu pour fonctionner convenablement avec un site Django (ou tout autre site web). En effet un site internet peut manipuler le code par le biais de plusieurs threads et processus, et Xapian ne peut avoir qu'un seul accès en écriture à sa base de données. Il est donc nécessaire de découpler ...</summary>

  <content type="text/html" mode="escaped"
           xml:space="preserve">Dans mon &lt;a href="http://programmation-python.org/sections/blog/2007_06_07_indexation-facile-rapide"&gt;post précéden&lt;/a&gt;t, je parlais de l'indexation avec Xapian. Le fonctionnement du paquet a du être revu pour fonctionner convenablement avec un site Django (ou tout autre site web). En effet un site internet peut manipuler le code par le biais de plusieurs threads et processus, et Xapian ne peut avoir qu'un seul accès en écriture à sa base de données. Il est donc nécessaire de découpler l'indexation des requêtes de recherche.&lt;br&gt;&lt;br&gt;Une des solutions est de maintenir sur le filesystem un fichier de lock pour s'assurer que la base n'est pas ouverte en écriture par deux threads au même moment, mais cette solution fonctionne mal en cas de crash de l'application. De plus, les données en cours d'indexation peuvent être perdues.&lt;br&gt;&lt;br&gt;La solution optimale est d'opter pour un pattern &lt;a href="http://fr.wikipedia.org/wiki/Mod%C3%A8le_producteur-consommateur"&gt;producers-consumer&lt;/a&gt; avec une pile persistente des données de travail, indépendante du site web, qui ne devient qu'un client parmi d'autres.&lt;br&gt;&lt;br&gt;Voici les modifications apportées au paquet pour mettre en place ce fonctionnement :&lt;br&gt;&lt;br&gt;&lt;ul&gt;&lt;li&gt;Les demandes d'indexation sont maintenant stockées dans une base de donnée sqlite. Comme &lt;a href="http://www.sqlalchemy.org/"&gt;SQLALchemy&lt;/a&gt; est employé, un passage à postgres ou mysql est direct.&lt;/li&gt;&lt;li&gt;Un thread est en charge de lire la base pour récupérer les demandes d'indexations et acter&lt;/li&gt;&lt;li&gt;L'API de recherche ouvre la base Xapian en lecture seule pour les requêtes&lt;/li&gt;&lt;/ul&gt;&lt;br&gt;Cette architecture offre en outre un fonctionnement rapide : lorsque des documents sont ajoutés ou modifiés dans le site, leur indexation est fait de manière asynchrone. Le système des signals est utilisé pour déclencher une indexation à chaque modification d'un document basé sur un model. Ce mécanisme, basé sur le framework d'events de Django, est expliqué ici: &lt;a href="http://www.mercurytide.com/whitepapers/django-signals/"&gt;http://www.mercurytide.com/whitepapers/django-signals/&lt;/a&gt;. &lt;br&gt;&lt;br&gt;Au final, pour utiliser le paquet il faut:&lt;br&gt;&lt;br&gt;&lt;ul&gt;&lt;li&gt;Lancer le thread en charge des indexations (via le script run.py)&lt;/li&gt;&lt;li&gt;Importer dans son code les modules searcher et indexer pour travailler&lt;/li&gt;&lt;/ul&gt;&lt;br&gt;Voici le doctest complet pour bien comprendre le fonctionnement :&lt;br&gt;
&lt;pre&gt;
=======
indexer
=======

The indexer provides:

- client-side modules : API for client to ask for indexations and query the
  Xapian database. When an indexation is asked, it is stored in a sql
  database;

- server-side application: a standalone thread that indexes what has been
  asked by reading the sql database.


Let's import the modules used by the client-side::

    &gt;&gt;&gt; import indexer
    &gt;&gt;&gt; import searcher

Let's reset the SQL DB first::

    &gt;&gt;&gt; indexer.reset()

Let's also reset the Xapian DB::

    &gt;&gt;&gt; from xapindexer import force_reset
    &gt;&gt;&gt; force_reset()

The Xapian DB should be empty now::

    &gt;&gt;&gt; searcher.corpus_size()
    0

Indexation
==========

Each indexable content has a unique id, and a text to index::

    &gt;&gt;&gt; uid = '1'
    &gt;&gt;&gt; text = 'my taylor is not rich anymore'

Let's index it::

    &gt;&gt;&gt; indexer.index_document(uid, text)

Another one::

    &gt;&gt;&gt; indexer.index_document('2', 'pluto is a dog')

Let's start the worker that is in charge of asynchronous indexation::

    &gt;&gt;&gt; from xapindexer import start_server
    &gt;&gt;&gt; start_server()

Let's wait a bit so the worker has the time to read the SQL Database
and do the work::

    &gt;&gt;&gt; import time
    &gt;&gt;&gt; while indexer.is_working():
    ...     time.sleep(0.2)

`is_working` looks in the SQL DB if there is some work left.

The Xapian DB has two documents now::

    &gt;&gt;&gt; searcher.corpus_size()
    2

Searching
=========

Let's search now, with `searcher`. Operator is AND by default::

    &gt;&gt;&gt; res = searcher.search('rich')
    &gt;&gt;&gt; list(res)
    ['1']
    &gt;&gt;&gt; res = searcher.search('pluto')
    &gt;&gt;&gt; list(res)
    ['2']
    &gt;&gt;&gt; res = searcher.search('dog')
    &gt;&gt;&gt; list(res)
    ['2']
    &gt;&gt;&gt; res = searcher.search('rich dog')
    &gt;&gt;&gt; list(res)
    []

Or operator::

    &gt;&gt;&gt; res = searcher.search('rich dog', or_=True)
    &gt;&gt;&gt; res = list(res)
    &gt;&gt;&gt; res.sort()
    &gt;&gt;&gt; res
    ['1', '2']

We have an API to detect if a document is present::

    &gt;&gt;&gt; searcher.document_exists('2')
    True
    &gt;&gt;&gt; searcher.document_exists('ttt')
    False

And another one to retrieve indexed terms::

    &gt;&gt;&gt; list(searcher.document_terms('2'))
    ['dog', 'is', 'pluto']


Reindexation
============

The document can also be reindexed::

    &gt;&gt;&gt; indexer.index_document('2', 'pluto is a cat')
    &gt;&gt;&gt; indexer.work_in_process()
    ([2], [])

Let's wait a bit::

    &gt;&gt;&gt; while indexer.is_working():
    ...     time.sleep(0.2)

Let's make sure the document has been reindexed::

    &gt;&gt;&gt; list(searcher.document_terms('2'))
    ['cat', 'is', 'pluto']

Then check the indexation has changed::

    &gt;&gt;&gt; res = searcher.search('rich dog', or_=True)
    &gt;&gt;&gt; list(res)
    ['1']

Or deleted::

    &gt;&gt;&gt; res = searcher.search('pluto')
    &gt;&gt;&gt; list(res)
    ['2']
    &gt;&gt;&gt; indexer.delete_document('2')
    &gt;&gt;&gt; while indexer.is_working():
    ...     time.sleep(0.2)
    &gt;&gt;&gt; res = searcher.search('pluto')
    &gt;&gt;&gt; list(res)
    []
&lt;/pre&gt;

&lt;br&gt;Sur la maquette que j'ai monté pour tester l'outil, j'ai été surpris de la rapidité de la solution. Le couple Xapian+Django permet de mettre en place un moteur de recherche très efficace. Lorsque le site en cours de conception sera terminé, je posterais un lien sur mon blog pour démo.&lt;br&gt;&lt;br&gt;Le code peut être récupéré dans xap ici: &lt;a href="http://hg.programmation-python.org/repositories/public/"&gt;http://hg.programmation-python.org/repositories/public/&lt;/a&gt;&lt;br&gt;&lt;br&gt;Prochains billets possibles sur ce sujet (à vous de choisir en commentant ce billet):&lt;br&gt;&lt;ul&gt;&lt;li&gt;commentaires détailés sur le code conçu&lt;br&gt;&lt;/li&gt;&lt;li&gt;explications sur les signaux dans Django&lt;/li&gt;&lt;li&gt;...&lt;br&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br&gt;</content>

  <id>tag:programmation-python.org:sections:blog:2007_06_12_serveur-d-indexation</id>
  <link rel="service.edit" type="application/atom+xml"
        href="http://programmation-python.org/sections/blog/2007_06_12_serveur-d-indexation/atom?2007_06_12_serveur-d-indexation"
        title="Edit Here - Serveur d'indexation pour Django avec Xapian" />
</entry>

  
  
      <entry xmlns="http://purl.org/atom/ns#"
       xmlns:dc="http://purl.org/dc/elements/1.1/">
     
  <title mode="escaped" type="text/html">Indexation facile et rapide avec Xapian</title>
  <link rel="alternate" type="text/html"
        href="http://programmation-python.org/sections/blog/2007_06_07_indexation-facile-rapide" />
  <issued>2007-06-08T09:39:40Z</issued>
  <modified>2007-06-08T09:39:40Z</modified>
  <created>2007-06-07T21:57:34Z</created>
  <draft xmlns="http://purl.org/atom-blog/ns#">false</draft>
  <author>
    <name>tarek</name>
  </author>
  
  
    <dc:subject>coding</dc:subject>
  
  
    <dc:subject>django</dc:subject>
  
  
  <summary type="text/html" mode="escaped">J'en avais parlé il y a quelques mois, Xapian est très simple à utiliser et à mettre en oeuvre pour des besoins légers d'indexation. Malgré son API très orientée page html (chaque document indexé l'est avec le contenu de la page), l'outil peut être utilisé pour fournir un moteur de recherche light rapide. Le système de Query qui pêchait encore il y a quelque temps (combinaisons limitées) est ...</summary>

  <content type="text/html" mode="escaped"
           xml:space="preserve">J'en avais parlé il y a quelques mois, Xapian est très simple à utiliser et à mettre en oeuvre pour des besoins légers d'indexation. Malgré son API très orientée &lt;i&gt;page html&lt;/i&gt; (chaque document indexé l'est avec le contenu de la page), l'outil peut être utilisé pour fournir un moteur de recherche light rapide. Le système de Query qui pêchait encore il y a quelque temps (combinaisons limitées) est maintenant plus complet.&lt;br&gt;&lt;br&gt;Xapian s'installe très facilement, ainsi que son binding Python (&lt;a href="http://www.xapian.org/"&gt;voir site&lt;/a&gt;)&lt;br&gt;&lt;br&gt;J'avais besoin d'un petit moteur pour un site que je suis en train de monter en Django. Voici le principe mise en oeuvre:&lt;br&gt;&lt;br&gt;&lt;ul&gt;&lt;li&gt;Création d'une base de type Flint&lt;/li&gt;&lt;li&gt;Indexation de documents&lt;/li&gt;&lt;li&gt;Recherches simples AND ou OR&lt;/li&gt;&lt;/ul&gt;&lt;br&gt;La base est créé par l'API &lt;i&gt;flint_open&lt;/i&gt;:&lt;br&gt;

&lt;pre&gt;&amp;gt;&amp;gt;&amp;gt; import xapian&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; DB = xapian.flint_open('file.db', xapian.DB_CREATE_OR_OPEN)&lt;br&gt;&lt;/pre&gt;


Puis chaque document est indexé par la création d'un Document et un appel successif à ses méthodes &lt;span style="font-style: italic;"&gt;add_term&lt;/span&gt; et &lt;i&gt;add_posting&lt;/i&gt;, sachant que &lt;i&gt;set_data&lt;/i&gt; n'est pas utilisé dans notre cas. &lt;br&gt;&lt;br&gt;&lt;ul&gt;&lt;li&gt;&lt;i&gt;set_data&lt;/i&gt; permet de définir le contenu du document à stocker, puisque le moteur prend aussi en charge les données.&lt;/li&gt;&lt;li&gt;&lt;i&gt;add_posting&lt;/i&gt; permet de stocker les mots-clefs associés au document, qui permettent de le retrouver dans une recherche.&lt;/li&gt;&lt;li&gt;&lt;i&gt;add_term&lt;/i&gt; est utilisé pour stocker la clé unique, préfixée d'un 'Q' &lt;br&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br&gt;Pour des besoins simples d'indexation, &lt;i&gt;set_data&lt;/i&gt; se contente de stocker un identifiant unique, comme un &lt;i&gt;uuid&lt;/i&gt; ou une url:&lt;br&gt;


&lt;pre&gt;&amp;gt;&amp;gt;&amp;gt; uri = '111'&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; doc = xapian.Document()&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; doc.add_term('Q%s' % uri, 1)&lt;br&gt;&lt;/pre&gt;

Enfin, chaque mot est associé au document avec &lt;i&gt;add_posting&lt;/i&gt;:&lt;br&gt;

&lt;pre&gt;&amp;gt;&amp;gt;&amp;gt; i = 1&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; for word in ('cat', 'pussy', 'cool'):&lt;br&gt;...     doc.add_posting(word, i)&lt;br&gt;...     i += 1&lt;br&gt;&lt;/pre&gt;

Puis le document ajouté à la base:&lt;br&gt;
&lt;pre&gt;&amp;gt;&amp;gt;&amp;gt; DB.add_document(doc)&lt;br&gt;&lt;/pre&gt;
&lt;br&gt;La recherche est ensuite effectuée par le biais d'un object Query:&lt;br&gt;
&lt;pre&gt;&amp;gt;&amp;gt;&amp;gt; enquire = xapian.Enquire(DB)&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; query = xapian.Query('pussy')&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; enquire.set_query(query)&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; res = enquire.get_mset(0, 100)&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; res[0].document.termlist().next().term[1:]&lt;br&gt;'111'&lt;br&gt;&lt;/pre&gt;

&lt;br&gt;Les API &lt;i&gt;delete_document&lt;/i&gt; et &lt;i&gt;replace_document&lt;/i&gt; permettent aussi de gérer la réindexation, en retrouvant le document déjà indexé par le biais d'une recherche sur le term qui sert de clef.&lt;br&gt;&lt;br&gt;Xapian fourni également des tokenizers pour faciliter le travail d'extraction des mots à associer au document. J'utilise pour ma part un tokenizer maison plus paramétrable. &lt;br&gt;&lt;br&gt;Si vous avez envie d'utiliser Xapian pour un projet Python, n'hésitez pas à récupérer le paquet (embryon en cours de conception) que j'ai fait sur mon repository. Il gère l'indexation, la réindexation, la suppression, etc.&lt;br&gt;&lt;br&gt;Repo (cliquer sur manifest, puis aller dans 'xap'):&amp;nbsp;&lt;a href="http://hg.programmation-python.org/repositories/public"&gt; http://hg.programmation-python.org/repositories/public/&lt;/a&gt;&lt;br&gt;&lt;br&gt;Il fournit une API extrêment simple à mettre en oeuvre. (c.f. le doctest dans doc/db.txt)&lt;br&gt;&lt;br&gt;Feedback welcome !&lt;br&gt;&lt;br&gt;&lt;br&gt;</content>

  <id>tag:programmation-python.org:sections:blog:2007_06_07_indexation-facile-rapide</id>
  <link rel="service.edit" type="application/atom+xml"
        href="http://programmation-python.org/sections/blog/2007_06_07_indexation-facile-rapide/atom?2007_06_07_indexation-facile-rapide"
        title="Edit Here - Indexation facile et rapide avec Xapian" />
</entry>

  
  
      <entry xmlns="http://purl.org/atom/ns#"
       xmlns:dc="http://purl.org/dc/elements/1.1/">
     
  <title mode="escaped" type="text/html">Slides JPF</title>
  <link rel="alternate" type="text/html"
        href="http://programmation-python.org/sections/blog/2007_06_05_slides-jpf" />
  <issued>2007-06-05T10:08:19Z</issued>
  <modified>2007-06-05T10:08:19Z</modified>
  <created>2007-06-05T10:07:52Z</created>
  <draft xmlns="http://purl.org/atom-blog/ns#">false</draft>
  <author>
    <name>tarek</name>
  </author>
  
  
    <dc:subject>afpy</dc:subject>
  
  
    <dc:subject>documentation</dc:subject>
  
  
    <dc:subject>evenements</dc:subject>
  
  
  <summary type="text/html" mode="escaped">Billet très rapide ;)mes slides des JFP :Présentation sur le DDDLe Keynote de démarrage des journéesN'hésitez pas à commenter ce billet pour toute question ou remarque</summary>

  <content type="text/html" mode="escaped"
           xml:space="preserve">Billet très rapide ;)&lt;br&gt;&lt;br&gt;mes slides des JFP :&lt;br&gt;&lt;br&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://journees.afpy.org/presentations/ddd-ziade/slides.html"&gt;Présentation sur le DDD&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://journees.afpy.org/presentations/ddd-ziade/keynote.html"&gt;Le Keynote de démarrage des journées&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br&gt;N'hésitez pas à commenter ce billet pour toute question ou remarque&lt;br&gt;</content>

  <id>tag:programmation-python.org:sections:blog:2007_06_05_slides-jpf</id>
  <link rel="service.edit" type="application/atom+xml"
        href="http://programmation-python.org/sections/blog/2007_06_05_slides-jpf/atom?2007_06_05_slides-jpf"
        title="Edit Here - Slides JPF" />
</entry>

  
  
      <entry xmlns="http://purl.org/atom/ns#"
       xmlns:dc="http://purl.org/dc/elements/1.1/">
     
  <title mode="escaped" type="text/html">Sondage sur le livre "Programmation Python"</title>
  <link rel="alternate" type="text/html"
        href="http://programmation-python.org/sections/blog/2007_05_25_sondage-sur-livre" />
  <issued>2007-05-25T08:08:55Z</issued>
  <modified>2007-05-25T08:08:55Z</modified>
  <created>2007-05-25T08:04:34Z</created>
  <draft xmlns="http://purl.org/atom-blog/ns#">false</draft>
  <author>
    <name>tarek</name>
  </author>
  
  
    <dc:subject>documentation</dc:subject>
  
  
  <summary type="text/html" mode="escaped">Une deuxième édition est prévue pour le livre Programmation Python, et je souhaiterais avoir l'avis des lecteurs pour améliorer l'ouvrage. Voici un questionnaire auquel vous pouvez me répondre par mail ou directement sur ce billet. Merci d'avance !1. Pour chacun des chapitres quels sont, selon vous, les points faibles à corriger:- Introduction:- Python pour quel usage ?: - Environnement de ...</summary>

  <content type="text/html" mode="escaped"
           xml:space="preserve">Une deuxième édition est prévue pour le livre Programmation Python, et je souhaiterais avoir l'avis des lecteurs pour améliorer l'ouvrage. Voici un questionnaire auquel vous pouvez me répondre par mail ou directement sur ce billet. Merci d'avance !&lt;br&gt;&lt;br&gt;1. Pour chacun des chapitres quels sont, selon vous, les points faibles à corriger:&lt;br&gt;&lt;br&gt;- Introduction:&lt;br&gt;- Python pour quel usage ?: &lt;br&gt;- Environnement de développement:&lt;br&gt;- Syntaxe du langage:&lt;br&gt;- Structuration du code:&lt;br&gt;- Primitives:&lt;br&gt;- Conventions de codage:&lt;br&gt;- Principaux modules 1: &lt;br&gt;- Principaux modules 2:&lt;br&gt;- Principaux modules 3:&lt;br&gt;- Exercices corrigés:&lt;br&gt;- Programmation par les tests:&lt;br&gt;- Bonnes pratioques et optimisation:&lt;br&gt;- POO:&lt;br&gt;- Annexes:&lt;br&gt;&lt;br&gt;2. Quelles sont les parties du livre qui vous ont paru trop longues ?&lt;br&gt;&lt;br&gt;3. Quelles sont les parties du livre qui vous ont paru trop courtes ?&lt;br&gt;&lt;br&gt;
4. Quels sont les sujets qui n'ont pas été traité, à tort ?&lt;br&gt;&lt;br&gt;5. Voici une liste de sujets qui se rajouteront à la deuxième édition&lt;br&gt;&lt;br&gt;- Python 3000&lt;br&gt;- Etude de cas&lt;br&gt;&lt;br&gt;En voyez vous d'autres que vous aimeriez voir aborder ?&lt;br&gt;&amp;nbsp;&lt;br&gt;&lt;br&gt;6. Qu'avez vous le plus apprécié dans le livre ?&lt;br&gt;&lt;br&gt;&lt;br&gt;
7. Qu'avez vous le plus moins apprécié dans le livre ?&lt;br&gt;&lt;br&gt;&lt;br&gt;Merci d'avance à ceux qui répondront !&lt;br&gt;&lt;br&gt;&lt;br&gt;</content>

  <id>tag:programmation-python.org:sections:blog:2007_05_25_sondage-sur-livre</id>
  <link rel="service.edit" type="application/atom+xml"
        href="http://programmation-python.org/sections/blog/2007_05_25_sondage-sur-livre/atom?2007_05_25_sondage-sur-livre"
        title="Edit Here - Sondage sur le livre &quot;Programmation Python&quot;" />
</entry>

  
  
      <entry xmlns="http://purl.org/atom/ns#"
       xmlns:dc="http://purl.org/dc/elements/1.1/">
     
  <title mode="escaped" type="text/html">Journées Python Francophone</title>
  <link rel="alternate" type="text/html"
        href="http://programmation-python.org/sections/blog/2007_05_23_journees-python" />
  <issued>2007-05-23T10:24:29Z</issued>
  <modified>2007-05-23T10:24:29Z</modified>
  <created>2007-05-23T10:24:28Z</created>
  <draft xmlns="http://purl.org/atom-blog/ns#">false</draft>
  <author>
    <name>tarek</name>
  </author>
  
  
    <dc:subject>evenements</dc:subject>
  
  
  <summary type="text/html" mode="escaped">Wow ! Les Journées Python Francophone se dérouleront dans moins de 15 jours et c'est déjà une énorme réussite pour l'association. De nombreux partenaires se sont joint à l'évènement, le programme est riche et très varié, et plus de 80 personnes se sont pré-inscrites sur le site.Cerise sur le gateau: pour ceux qui ne peuvent pas faire le déplacement, Merlin Rocket va diffuser les conférences sur ...</summary>

  <content type="text/html" mode="escaped"
           xml:space="preserve">Wow ! &lt;a href="http://journees.afpy.org/"&gt;Les Journées Python Francophone&lt;/a&gt; se dérouleront dans moins de 15 jours et c'est déjà une énorme réussite pour l'association. De nombreux &lt;a href="http://journees.afpy.org/partenaires"&gt;partenaires&lt;/a&gt; se sont joint à l'évènement, &lt;a href="http://journees.afpy.org/programme"&gt;le programme&lt;/a&gt; est riche et très varié, et plus de 80 personnes se sont pré-inscrites sur le site.&lt;br&gt;&lt;br&gt;Cerise sur le gateau: pour ceux qui ne peuvent pas faire le déplacement, &lt;a href="http://www.merlinrocket.fr/"&gt;Merlin Rocket&lt;/a&gt; va diffuser les conférences sur Second Life !&lt;br&gt;&lt;br&gt;Ces journées, c'est une occasion unique, outre pour venir voir les conférences bien sûr, de venir rencontrer les gens de la communauté Python francophone. &lt;br&gt;&lt;br&gt;J'y serais en compagnie de mon fils, avec qui j'irais faire un tour à la &lt;a href="http://www.cite-sciences.fr/francais/ala_cite/expo/tempo/cradexpo/cradexpo_flash.html"&gt;CradExpo&lt;/a&gt; (ca rentre pile-poil dans ses préoccupations actuelles ;) ). Et comme c'est la fête des mères pendant les journées, n'oubliez pas de vous inscrire sur le site pour lui faire gagner un magnifique mug ActiveState par exemple, qu'elle pourra montrer avec fierté à ses proches, la larme à l'oeil, en disant : "C'est un cadeau de mon fils (ma fille), il (elle) est à la pointe des nouvelles technologies grâce à Python, je suis tellement fière !"&lt;br&gt;</content>

  <id>tag:programmation-python.org:sections:blog:2007_05_23_journees-python</id>
  <link rel="service.edit" type="application/atom+xml"
        href="http://programmation-python.org/sections/blog/2007_05_23_journees-python/atom?2007_05_23_journees-python"
        title="Edit Here - Journées Python Francophone" />
</entry>

  
  
      <entry xmlns="http://purl.org/atom/ns#"
       xmlns:dc="http://purl.org/dc/elements/1.1/">
     
  <title mode="escaped" type="text/html">Petit guide à l'usage du développeur agile</title>
  <link rel="alternate" type="text/html"
        href="http://programmation-python.org/sections/blog/2007_05_03_petit-guide-usage-du" />
  <issued>2007-06-07T23:00:13Z</issued>
  <modified>2007-06-07T23:00:13Z</modified>
  <created>2007-05-03T19:42:38Z</created>
  <draft xmlns="http://purl.org/atom-blog/ns#">false</draft>
  <author>
    <name>tarek</name>
  </author>
  
  
    <dc:subject>documentation</dc:subject>
  
  
  <summary type="text/html" mode="escaped">
Je suis ravi de vous annoncer la parution prochaine (le 16 août) de mon deuxième livre. Il paraîtra chez Dunod et sera orienté méthodologie, mais appliquée, et de manière concrète, à Python.J'attends le feu vert de l'éditeur pour publier l'index, et quelques morceaux. En attendantvoici la liste des chapitres:- Introduction- Environnement de développement- Architecture- Développement- Bonnes ...</summary>

  <content type="text/html" mode="escaped"
           xml:space="preserve">&lt;img src="http://journees.afpy.org/presentations/ddd-ziade/media/guide.png"&gt;
&lt;br&gt;&lt;br&gt;Je suis ravi de vous annoncer la parution prochaine (le 16 août) de mon deuxième livre. Il paraîtra chez Dunod et sera orienté méthodologie, mais appliquée, et de manière concrète, à Python.&lt;br&gt;&lt;br&gt;J'attends le feu vert de l'éditeur pour publier l'index, et quelques morceaux. En attendant&lt;br&gt;voici la liste des chapitres:&lt;br&gt;&lt;br&gt;- Introduction&lt;br&gt;- Environnement de développement&lt;br&gt;- Architecture&lt;br&gt;- Développement&lt;br&gt;- Bonnes pratiques&lt;br&gt;- Développement dirigé par les tests&lt;br&gt;- Développement dirigé par la documentation&lt;br&gt;- Gestion de projet&amp;nbsp; &lt;br&gt;&lt;br&gt;Ce livre vient en format réduit (192 pages) et se détache de tous les éléments qui peuvent être trouvés facilement sur le net. Le lectorat cible est le développeur qui a un peu d'expérience en développement, mais pas forcément en Python, et le chef de projet qui a en charge le développement d'un projet Python.&lt;br&gt;&lt;br&gt;Son objectif est de:&lt;br&gt;&lt;br&gt;&lt;ul&gt;&lt;li&gt;sensibiliser le développeur Python sur la qualité du code qu'il produit, et de lui proposer des méthodes &lt;i&gt;agiles&lt;/i&gt; pour l'améliorer;&lt;/li&gt;&lt;li&gt;sensibiliser les chefs de projet sur les techniques agiles de gestion de projet.&lt;/li&gt;&lt;/ul&gt;&lt;br&gt;Il complètera mon livre précédent qui lui est dans un format plus complet et moins orienté méthodologie. Ce dernier sera d'ailleurs mis à jour très prochainement et j'inviterais les lecteurs interessés à me proposer des modifications, améliorations, etc.&lt;br&gt;&lt;br&gt;Stay tuned for more infos !&lt;br&gt;&lt;br&gt;</content>

  <id>tag:programmation-python.org:sections:blog:2007_05_03_petit-guide-usage-du</id>
  <link rel="service.edit" type="application/atom+xml"
        href="http://programmation-python.org/sections/blog/2007_05_03_petit-guide-usage-du/atom?2007_05_03_petit-guide-usage-du"
        title="Edit Here - Petit guide à l'usage du développeur agile" />
</entry>

  
  
      <entry xmlns="http://purl.org/atom/ns#"
       xmlns:dc="http://purl.org/dc/elements/1.1/">
     
  <title mode="escaped" type="text/html">Critique de livre: The Tipping Point</title>
  <link rel="alternate" type="text/html"
        href="http://programmation-python.org/sections/blog/2007_03_14_critique-livre-the" />
  <issued>2007-05-21T09:54:41Z</issued>
  <modified>2007-05-21T09:54:41Z</modified>
  <created>2007-03-14T12:39:18Z</created>
  <draft xmlns="http://purl.org/atom-blog/ns#">false</draft>
  <author>
    <name>tarek</name>
  </author>
  
  
    <dc:subject>livre</dc:subject>
  
  
  <summary type="text/html" mode="escaped">

En achetant ce livre, j'avais peur qu'il soit trop emprunt de culture Américaine pour que je puisse comprendre précisément ce que Malcom Gladwell décrit, et le retrouver dans un contexte culturel Européen. Finalement, mise à part quelques références américano-américaines, ce livre reste  tout à fait limpide et se lit comme un livre de la bibliothèque verte ;).Le Tipping Point c'est ce ...</summary>

  <content type="text/html" mode="escaped"
           xml:space="preserve">&lt;a href="http://www.amazon.fr/dp/0316346624?tag=programmation-21&amp;amp;camp=1414&amp;amp;creative=6410&amp;amp;linkCode=as1&amp;amp;creativeASIN=0316346624&amp;amp;adid=186AM58JT87SA1288XEQ&amp;amp;"&gt;&lt;img src="http://programmation-python.org/media/tipping.jpg"&gt;
&lt;/a&gt;
&lt;br&gt;&lt;br&gt;En achetant ce livre, j'avais peur qu'il soit trop emprunt de culture Américaine pour que je puisse comprendre précisément ce que &lt;b&gt;Malcom Gladwell&lt;/b&gt; décrit, et le retrouver dans un contexte culturel Européen. Finalement, mise à part quelques références américano-américaines, ce livre reste&amp;nbsp; tout à fait limpide et se lit comme un livre de la bibliothèque verte ;).&lt;br&gt;&lt;br&gt;Le &lt;b&gt;Tipping Point&lt;/b&gt; c'est ce moment particulier, quantique, qui fait basculer une mode, une façon de penser ou encore une idée, du quasi-anonymat vers un phénomène de société. Gladwell, dans un style journalistique très agréable décortique ce phénomène par le biais de nombreux exemples pour proposer &lt;b&gt;un modèle basé sur l'épidémiologie&lt;/b&gt;.&amp;nbsp; &lt;br&gt;&lt;br&gt;Ce livre s'addresse à toutes les personnes désireuses de mieux propager leurs idées, ou tout simplement curieuses de mieux comprendre pourquoi le badge revient à la mode !&lt;br&gt;&lt;br&gt;Ce qu'il en ressort est une meilleure compréhension des phénomènes de masse, et, que vous soyez dans le marketing, le développement ou tout autre activité "informatisée" un meilleur usage de tous les outils actuels (web 2.0) axés sur &lt;b&gt;le social tagging&lt;/b&gt; (flickr, digg, etc.).&lt;br&gt;&lt;br&gt;&lt;br&gt;</content>

  <id>tag:programmation-python.org:sections:blog:2007_03_14_critique-livre-the</id>
  <link rel="service.edit" type="application/atom+xml"
        href="http://programmation-python.org/sections/blog/2007_03_14_critique-livre-the/atom?2007_03_14_critique-livre-the"
        title="Edit Here - Critique de livre: The Tipping Point" />
</entry>

  
  
      <entry xmlns="http://purl.org/atom/ns#"
       xmlns:dc="http://purl.org/dc/elements/1.1/">
     
  <title mode="escaped" type="text/html">Les cinq lois de la programmation évolutive</title>
  <link rel="alternate" type="text/html"
        href="http://programmation-python.org/sections/blog/2007_03_14_cinq-lois-programmation" />
  <issued>2007-03-29T12:00:51Z</issued>
  <modified>2007-03-29T12:00:51Z</modified>
  <created>2007-03-14T10:04:15Z</created>
  <draft xmlns="http://purl.org/atom-blog/ns#">false</draft>
  <author>
    <name>tarek</name>
  </author>
  
  
    <dc:subject>coding</dc:subject>
  
  
  <summary type="text/html" mode="escaped">Ecrire des programmes qui fonctionnent est à la portée de chacun. Surtout en Python ;). La difficulté principale est de réussir à écrire des programmes qui évoluent dans le bon sens, et éviter l'effet spaghetti*. Les cinq lois énoncées ci-dessous synthétisent les bonnes pratiques à adopter pour favoriser une croissance contrôlée des programmes.Les bon noms font les bons amisSoigne ta ...</summary>

  <content type="text/html" mode="escaped"
           xml:space="preserve">Ecrire des programmes qui fonctionnent est à la portée de chacun. Surtout en Python ;). La difficulté principale est de réussir à écrire des programmes qui évoluent dans le bon sens, et éviter &lt;i&gt;l'effet spaghetti&lt;/i&gt;*. Les cinq lois énoncées ci-dessous synthétisent les bonnes pratiques à adopter pour favoriser une croissance contrôlée des programmes.&lt;br&gt;&lt;br&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;Les bon noms font les bons amis&lt;/b&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;Soigne ta signature&lt;/b&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;Ecourter les conversations&lt;/b&gt;&lt;br&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;Ne jamais radoter&lt;/b&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;Diviser pour mieux régner&lt;/b&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br&gt;&lt;h3&gt;&lt;b&gt;Les bon noms font les bons amis&lt;/b&gt;&lt;/h3&gt;&lt;b&gt;&lt;br&gt;&lt;/b&gt;Choisissez avec soin le
nom de vos variables, modules, fonctions, classes et méthodes. Chacun
d'entre eux doit être explicite et indiquer clairement son objectif.&lt;br&gt;&lt;br&gt;Quelques pistes:&lt;br&gt;&lt;br&gt;&lt;ul&gt;&lt;li&gt;Respectez le &lt;a href="http://www.python.org/dev/peps/pep-0008/"&gt;PEP8&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Utilisez des conventions pour les méthodes et fonctions...&lt;/li&gt;&lt;ul&gt;&lt;li&gt;qui retournent des séquences : conjugez le nom au pluriel ou ajoutez un suffixe explicite comme 'list' (getElements, itemList, ...)&lt;/li&gt;&lt;li&gt;qui renvoient un booléen: préfixez de 'is' ou 'has'&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;Attention à la redondance dans les noms: les méthodes d'une classe par exemple ne doivent pas avoir un nom dont une partie du sens est donné par la classe:&lt;/li&gt;&lt;ul&gt;&lt;li&gt;MaList.getList() -&amp;gt; MaList.get()&lt;br&gt;&lt;/li&gt;&lt;li&gt;RS232.rs232_read() -&amp;gt; RS232.read()&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;b&gt;&lt;br&gt;&lt;/b&gt;&lt;h3&gt;&lt;b&gt;Soigne ta signature&lt;/b&gt;&lt;/h3&gt;&lt;br&gt;Les arguments de chaque méthode ou fonction doivent également être
précis. Eviter les signatures magiques avec *args et autres **kw, qui
rendent les interdépendances floues.&lt;br&gt;&lt;br&gt;Quelques cas particuliers:&lt;br&gt;&lt;ul&gt;&lt;li&gt;Les fonctions de traitement de formulaires dans la programmation web&lt;/li&gt;&lt;li&gt;Les decorators appliqués sur des fonctions dont les paramètres ne sont pas connus&lt;/li&gt;&lt;li&gt;Plus globalement: Les briques intermédiaires en charge de relayer des informations sans connaitre les partis&lt;/li&gt;&lt;/ul&gt;&lt;b&gt;&lt;br&gt;&lt;/b&gt;&lt;h3&gt;&lt;b&gt;Ecourter les conversations&lt;/b&gt;&lt;/h3&gt;&lt;br&gt;Lorsqu'un élément (classe, module, etc.) est utilisé dans du code, si
plusieurs appels successifs sont effectués pour l'utiliser (sans ou
avec peu d'interactions), ses APIs doivent être modifiées pour écourter
les échanges au maximum. Le module &lt;i&gt;__init__&lt;/i&gt; d'un paquet est un bon outil pour synthétiser son utilisation.&lt;br&gt;&lt;br&gt;Exemple de conversation trop bavarde:&lt;br&gt;
&lt;pre&gt;
from Paquet import misfit
from Paquet import cat

params = misfit.makeParams()
truc = cat.generateTruc(params)
bidule = cat.pondBiduleAvecTruc(truc)
&lt;/pre&gt;
&lt;br&gt;Les apis du Paquet et de ses modules peuvent être améliorés pour obtenir:&lt;br&gt;
&lt;pre&gt;
from Paquet import pondBidule

bidule = pondBidule()
&lt;/pre&gt;
&lt;br&gt;Le module __init__ joue alors le rôle d'intérmédiaire entre cat et misfit&lt;br&gt;&lt;b&gt;&lt;br&gt;&lt;/b&gt;&lt;h3&gt;&lt;b&gt;Ne jamais radoter&lt;/b&gt;&lt;/h3&gt;&lt;br&gt;L'ennemi du code est le doublon. Dès que deux blocs présentent des similitudes, il est nécessaire de les réunir.&lt;br&gt;&lt;b&gt;&lt;br&gt;&lt;/b&gt;&lt;h3&gt;&lt;b&gt;Diviser pour mieux régner&lt;/b&gt;&lt;/h3&gt;&lt;br&gt;une fonction ne devrait jamais dépasser un &lt;i&gt;écran&lt;/i&gt;.
Il est nécessaire de la subdiviser le cas écheant. Il en va de même
pour les classes, modules, et paquets: il ne faut pas avoir peur de
diviser son paquet en une multitudes de petits paquets.&lt;i&gt;&lt;br&gt;&lt;/i&gt;&lt;br&gt;&lt;i&gt;*&lt;b&gt;spaghetticus effectus&lt;/b&gt;: transformation d'un programme en un bloc monolithique ou chaque élément ne peut plus évoluer indépendamment des autres. Porte aussi le nom de &lt;b&gt;pieuvre à 6 têtes&lt;/b&gt; dans la mythologie geek.&lt;br&gt;&lt;br&gt;&lt;/i&gt;</content>

  <id>tag:programmation-python.org:sections:blog:2007_03_14_cinq-lois-programmation</id>
  <link rel="service.edit" type="application/atom+xml"
        href="http://programmation-python.org/sections/blog/2007_03_14_cinq-lois-programmation/atom?2007_03_14_cinq-lois-programmation"
        title="Edit Here - Les cinq lois de la programmation évolutive" />
</entry>

  
  
      <entry xmlns="http://purl.org/atom/ns#"
       xmlns:dc="http://purl.org/dc/elements/1.1/">
     
  <title mode="escaped" type="text/html">Slides PyCon 2007</title>
  <link rel="alternate" type="text/html"
        href="http://programmation-python.org/sections/blog/2007_02_24_slides-pycon-2007" />
  <issued>2007-02-24T16:25:40Z</issued>
  <modified>2007-02-24T16:25:40Z</modified>
  <created>2007-02-24T16:24:45Z</created>
  <draft xmlns="http://purl.org/atom-blog/ns#">false</draft>
  <author>
    <name>tarek</name>
  </author>
  
  
    <dc:subject>documentation</dc:subject>
  
  
  <summary type="text/html" mode="escaped">Je suis actuellement à Dallas. J.R. a vraiment pris un coup de vieux...En attendant d'autres photos de mon voyage à Dallas, et des billets sur les présentations que je regarde, voici les slides de mon tutoriel de Jeudi:S5: http://programmation-python.org/pycommunity/pycon/PyCon07/slides.htmlreST: http://programmation-python.org/pycommunity/pycon/PyCon07/slides.txt </summary>

  <content type="text/html" mode="escaped"
           xml:space="preserve">Je suis actuellement à Dallas. J.R. a vraiment pris un coup de vieux...&lt;br&gt;&lt;br&gt;&lt;img src="http://upload.wikimedia.org/wikipedia/en/7/7f/LarryHagman05Feb2006.jpg"&gt;&lt;br&gt;&lt;br&gt;En attendant d'autres photos de mon voyage à Dallas, et des billets sur les présentations que je regarde, voici les slides de mon tutoriel de Jeudi:&lt;br&gt;&lt;br&gt;&lt;ul&gt;&lt;li&gt;S5: &lt;a href="../../../../../../pycommunity/pycon/PyCon07/slides.html" title="S5 Slides" target="_blank" mce_href="http://programmation-python.org/pycommunity/pycon/PyCon07/slides.html"&gt;http://programmation-python.org/pycommunity/pycon/PyCon07/slides.html&lt;/a&gt;&lt;/li&gt;&lt;li&gt;reST: &lt;a href="../../../../../../pycommunity/pycon/PyCon07/slides.txt" title="reST slides" target="_blank" mce_href="http://programmation-python.org/pycommunity/pycon/PyCon07/slides.txt"&gt;http://programmation-python.org/pycommunity/pycon/PyCon07/slides.txt&lt;/a&gt; &lt;br&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br&gt;&lt;br&gt;</content>

  <id>tag:programmation-python.org:sections:blog:2007_02_24_slides-pycon-2007</id>
  <link rel="service.edit" type="application/atom+xml"
        href="http://programmation-python.org/sections/blog/2007_02_24_slides-pycon-2007/atom?2007_02_24_slides-pycon-2007"
        title="Edit Here - Slides PyCon 2007" />
</entry>

  
  
      <entry xmlns="http://purl.org/atom/ns#"
       xmlns:dc="http://purl.org/dc/elements/1.1/">
     
  <title mode="escaped" type="text/html">PyCommunity 0.1 bientôt dans les bacs</title>
  <link rel="alternate" type="text/html"
        href="http://programmation-python.org/sections/blog/2007_02_11_pycommunity-0-1-bientot" />
  <issued>2007-02-24T21:15:02Z</issued>
  <modified>2007-02-24T21:15:02Z</modified>
  <created>2007-02-11T22:59:51Z</created>
  <draft xmlns="http://purl.org/atom-blog/ns#">false</draft>
  <author>
    <name>tarek</name>
  </author>
  
  
    <dc:subject>coding</dc:subject>
  
  
    <dc:subject>cookbook</dc:subject>
  
  
    <dc:subject>documentation</dc:subject>
  
  
    <dc:subject>tests</dc:subject>
  
  
    <dc:subject>zope</dc:subject>
  
  
  <summary type="text/html" mode="escaped">Le projet PyCommunity, que je package en ce moment pour PyCon, est bientôt visible. Je viens d'en parler sur mon blog anglais. (un peu paresseux ce soir, de réécrire un billet complet).J'ai mis en ligne un exemple de génération ici: http://programmation-python.org/pycommunity/qui explique aussi un peu plus en détail le principe.Le code est visible dans un repository Mercurial ici: ...</summary>

  <content type="text/html" mode="escaped"
           xml:space="preserve">Le projet PyCommunity, que je package en ce moment pour PyCon, est bientôt visible. &lt;a href="http://tarekziade.wordpress.com/2007/02/11/pycommunity-01-almost-ready/"&gt;Je viens d'en parler sur mon blog anglais&lt;/a&gt;. (un peu paresseux ce soir, de réécrire un billet complet).&lt;br&gt;&lt;br&gt;J'ai mis en ligne un exemple de génération ici: &lt;a href="http://programmation-python.org/pycommunity/"&gt;http://programmation-python.org/pycommunity/&lt;/a&gt;&lt;br&gt;qui explique aussi un peu plus en détail le principe.&lt;br&gt;&lt;br&gt;Le code est visible dans un repository Mercurial ici:&lt;a href="http://hg.programmation-python.org/repositories/public"&gt; http://hg.programmation-python.org/repositories/public&lt;/a&gt;&lt;br&gt;&lt;br&gt;Enfin, un egg est accessible ici:&lt;a href="http://programmation-python.org/pycommunity/PyCommunity-0.1a-py2.5.egg"&gt; http://programmation-python.org/pycommunity/PyCommunity-0.1a-py2.5.egg&lt;/a&gt;&lt;br&gt;&lt;br&gt;Et peut être installé avec easy_install:&lt;br&gt;&lt;br&gt;sudo easy_install pycommunity&lt;br&gt;&lt;br&gt;</content>

  <id>tag:programmation-python.org:sections:blog:2007_02_11_pycommunity-0-1-bientot</id>
  <link rel="service.edit" type="application/atom+xml"
        href="http://programmation-python.org/sections/blog/2007_02_11_pycommunity-0-1-bientot/atom?2007_02_11_pycommunity-0-1-bientot"
        title="Edit Here - PyCommunity 0.1 bientôt dans les bacs" />
</entry>

  
  
      <entry xmlns="http://purl.org/atom/ns#"
       xmlns:dc="http://purl.org/dc/elements/1.1/">
     
  <title mode="escaped" type="text/html">Bloggeurs de la Planète Francophone</title>
  <link rel="alternate" type="text/html"
        href="http://programmation-python.org/sections/blog/2007_02_04_hommage-aux-bloggeurs" />
  <issued>2007-02-04T13:06:10Z</issued>
  <modified>2007-02-04T13:06:10Z</modified>
  <created>2007-02-04T10:24:25Z</created>
  <draft xmlns="http://purl.org/atom-blog/ns#">false</draft>
  <author>
    <name>tarek</name>
  </author>
  
  
    <dc:subject>documentation</dc:subject>
  
  
  <summary type="text/html" mode="escaped">Les blogs Python sympas et actifs en ce moment:Kib's Blog: Actif depuis 5 mois, Kib nous fait suivre le développement de son blog en Django, publie une sélection régulière de ses liens.Biologeek: Issu de la planète Ubuntu, David s'intéresse beaucoup à Python et nous offre des billets de qualité sur le sujet. Les personnes qui s'intéressent à cette distribution, s'intéresseront à Python grâce à ...</summary>

  <content type="text/html" mode="escaped"
           xml:space="preserve">Les blogs Python sympas et actifs en ce moment:&lt;br&gt;&lt;br&gt;&lt;a href="http://kib2.webfactional.com/"&gt;Kib's Blog&lt;/a&gt;: Actif depuis 5 mois, Kib nous fait suivre le développement de son blog en Django, publie une sélection régulière de ses liens.&lt;br&gt;&lt;br&gt;&lt;a href="http://www.biologeek.com/journal/index.php/Python"&gt;Biologeek&lt;/a&gt;: Issu de la planète Ubuntu, David s'intéresse beaucoup à Python et nous offre des billets de qualité sur le sujet. Les personnes qui s'intéressent à cette distribution, s'intéresseront à Python grâce à son blog, qui fait le lien entre les deux mondes.&lt;br&gt;&lt;br&gt;Si vous en connaissez d'autre n'hésitez pas à commenter ce billet&lt;br&gt;&lt;br&gt;&lt;br&gt;</content>

  <id>tag:programmation-python.org:sections:blog:2007_02_04_hommage-aux-bloggeurs</id>
  <link rel="service.edit" type="application/atom+xml"
        href="http://programmation-python.org/sections/blog/2007_02_04_hommage-aux-bloggeurs/atom?2007_02_04_hommage-aux-bloggeurs"
        title="Edit Here - Bloggeurs de la Planète Francophone" />
</entry>

  
  
      <entry xmlns="http://purl.org/atom/ns#"
       xmlns:dc="http://purl.org/dc/elements/1.1/">
     
  <title mode="escaped" type="text/html">Slides Solutions Linux</title>
  <link rel="alternate" type="text/html"
        href="http://programmation-python.org/sections/blog/2007_02_01_slides-solutions-linux" />
  <issued>2007-02-01T10:23:02Z</issued>
  <modified>2007-02-01T10:23:02Z</modified>
  <created>2007-02-01T10:12:26Z</created>
  <draft xmlns="http://purl.org/atom-blog/ns#">false</draft>
  <author>
    <name>tarek</name>
  </author>
  
  
    <dc:subject>evenements</dc:subject>
  
  
  <summary type="text/html" mode="escaped">Voici les slides de ma présentation d'hier. Le salon était un peu plus rempli que la veille, et s'est terminé par une session nocturne chez Emencia, avec Maik Roeder, Kamon Ayeva, Kit Blake et d'autres membres de la communauté Zope.Maik nous a présenté un nouvel outil de tests fonctionnels assez poussé qu'il est en train d'élaborer. Vivement que ce soit releasé. :)
</summary>

  <content type="text/html" mode="escaped"
           xml:space="preserve">Voici les slides de ma présentation d'hier. Le salon était un peu plus rempli que la veille, et s'est terminé par une session nocturne chez Emencia, avec Maik Roeder, Kamon Ayeva, Kit Blake et d'autres membres de la communauté Zope.&lt;br&gt;&lt;br&gt;Maik nous a présenté un nouvel outil de tests fonctionnels assez poussé qu'il est en train d'élaborer. Vivement que ce soit releasé. :)&lt;br&gt;&lt;br&gt;
&lt;img width="600" height="480" src="http://programmation-python.org/media/IMGP0841.JPG"&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;</content>

  <id>tag:programmation-python.org:sections:blog:2007_02_01_slides-solutions-linux</id>
  <link rel="service.edit" type="application/atom+xml"
        href="http://programmation-python.org/sections/blog/2007_02_01_slides-solutions-linux/atom?2007_02_01_slides-solutions-linux"
        title="Edit Here - Slides Solutions Linux" />
</entry>

  
  
      <entry xmlns="http://purl.org/atom/ns#"
       xmlns:dc="http://purl.org/dc/elements/1.1/">
     
  <title mode="escaped" type="text/html">Mercredi 31 janvier 2007 - 16h - Solutions Linux - Développement Dirigé par la Documentation</title>
  <link rel="alternate" type="text/html"
        href="http://programmation-python.org/sections/blog/2007_01_30_mercredi-31-janvier-2007" />
  <issued>2007-01-30T17:01:59Z</issued>
  <modified>2007-01-30T17:01:59Z</modified>
  <created>2007-01-30T17:01:58Z</created>
  <draft xmlns="http://purl.org/atom-blog/ns#">false</draft>
  <author>
    <name>tarek</name>
  </author>
  
  
    <dc:subject>coding</dc:subject>
  
  
    <dc:subject>documentation</dc:subject>
  
  
    <dc:subject>evenements</dc:subject>
  
  
  <summary type="text/html" mode="escaped">Si vous êtes de passage mercredi à Solutions Linux,  je présente au village ASS2L un petit sujet de 20 minutes sur la programmation dirigée par la documentation.Cette méthode de programmation agile permet d'intégrer de manière transparente la constitution de la documentation technique dans le cycle de développement. Elle résoud les problèmatiques de mise à jour de la documentation des ...</summary>

  <content type="text/html" mode="escaped"
           xml:space="preserve">Si vous êtes de passage mercredi à Solutions Linux,&amp;nbsp; je présente au &lt;a href="http://www.zwook.org/news/zwo_modules/news/read_news?id=1169748376.9&amp;amp;instid=news"&gt;village ASS2L&lt;/a&gt; un petit sujet de 20 minutes sur la programmation dirigée par la documentation.&lt;br&gt;&lt;br&gt;Cette méthode de programmation agile permet d'intégrer de manière transparente la constitution de la documentation technique dans le cycle de développement. Elle résoud les problèmatiques de mise à jour de la documentation des logiciels et permet un meilleur suivi des développements par la communauté lorsque le logiciel est open source, grâce à la génération automatique de pages html basées sur le contenu des documents.&lt;br&gt;&lt;br&gt;C'est une méthode qui est appliquée au développement d'&lt;a href="http://www.emenciacommerce.com/fr/"&gt;ECS, framework d'e-commerce Python&lt;/a&gt; developpé par &lt;a href="http://emencia.fr/"&gt;Emencia, ma nouvelle entreprise&lt;/a&gt; (Python powa ! ;) ).&lt;br&gt;&lt;br&gt;A terme, le site d'ECS concernant les modules seront générés à la volée à chaque modification du code par le biais de PyCommunity, l'outil de synchronisation entre un repository de code et un site web, que je suis en train de développer.&lt;br&gt;&lt;br&gt;&lt;br&gt;</content>

  <id>tag:programmation-python.org:sections:blog:2007_01_30_mercredi-31-janvier-2007</id>
  <link rel="service.edit" type="application/atom+xml"
        href="http://programmation-python.org/sections/blog/2007_01_30_mercredi-31-janvier-2007/atom?2007_01_30_mercredi-31-janvier-2007"
        title="Edit Here - Mercredi 31 janvier 2007 - 16h - Solutions Linux - Développement Dirigé par la Documentation" />
</entry>

  
  
      <entry xmlns="http://purl.org/atom/ns#"
       xmlns:dc="http://purl.org/dc/elements/1.1/">
     
  <title mode="escaped" type="text/html">commit hook en Python pour mercurial</title>
  <link rel="alternate" type="text/html"
        href="http://programmation-python.org/sections/blog/2006_12_27_commit-hook-en-python" />
  <issued>2006-12-27T00:18:23Z</issued>
  <modified>2006-12-27T00:18:23Z</modified>
  <created>2006-12-26T23:55:49Z</created>
  <draft xmlns="http://purl.org/atom-blog/ns#">false</draft>
  <author>
    <name>tarek</name>
  </author>
  
  
    <dc:subject>coding</dc:subject>
  
  
  <summary type="text/html" mode="escaped">Mercurial est un système distribué de gestion de sources écrit en Python. Il permet à des développeurs de travailler avec leur code et de le versionner comme avec Subversion, mais sans avoir à dépendre d'un serveur centralisé: chaque modification est conservée localement, et le développeur peut à tout moment se synchroniser avec un autre repository, qu'il soit sur un serveur ou sur un autre poste ...</summary>

  <content type="text/html" mode="escaped"
           xml:space="preserve">&lt;a href="http://www.selenic.com/mercurial/wiki/index.cgi"&gt;Mercurial&lt;/a&gt; est un &lt;i&gt;système distribué de gestion de sources&lt;/i&gt; écrit en Python. Il permet à des développeurs de travailler avec leur code et de le versionner comme avec &lt;a href="http://subversion.tigris.org/"&gt;Subversion&lt;/a&gt;, mais sans avoir à dépendre d'un serveur centralisé: chaque modification est conservée localement, et le développeur peut à tout moment se synchroniser avec un autre repository, qu'il soit sur un serveur ou sur un autre poste de développement.&lt;br&gt;&lt;br&gt;Un repository Mercurial est accessible entres autres en SSH, et peut être recopié localement pour être modifié (commande &lt;i&gt;clone&lt;/i&gt;), puis mis à jour avec la commande &lt;i&gt;push&lt;/i&gt;. L'utilisation de Mercurial est très similaire à celle de Subversion:&lt;br&gt;&lt;br&gt;
&lt;pre&gt;dabox:~ tarek$ hg&lt;br&gt;Mercurial Distributed SCM&lt;br&gt;&lt;br&gt;basic commands (use "hg help" for the full list or option "-v" for details):&lt;br&gt;&lt;br&gt; add        add the specified files on the next commit&lt;br&gt; annotate   show changeset information per file line&lt;br&gt; clone      make a copy of an existing repository&lt;br&gt; commit     commit the specified files or all outstanding changes&lt;br&gt; diff       diff repository (or selected files)&lt;br&gt; export     dump the header and diffs for one or more changesets&lt;br&gt; init       create a new repository in the given directory&lt;br&gt; log        show revision history of entire repository or files&lt;br&gt; parents    show the parents of the working dir or revision&lt;br&gt; pull       pull changes from the specified source&lt;br&gt; push       push changes to the specified destination&lt;br&gt; remove     remove the specified files on the next commit&lt;br&gt; revert     revert files or dirs to their states as of some revision&lt;br&gt; serve      export the repository via HTTP&lt;br&gt; status     show changed files in the working directory&lt;br&gt; update     update or merge working directory&lt;br&gt;&lt;/pre&gt;&lt;br&gt;Mettre en place un projet basé sur Mercurial consiste donc à mettre à disposition des développeurs un repository via un utilisateur SSH. Cette mise en place est expliquée sur cette page : &lt;a href="http://www.selenic.com/mercurial/wiki/index.cgi/MultipleCommitters"&gt;http://www.selenic.com/mercurial/wiki/index.cgi/MultipleCommitters&lt;/a&gt;.&lt;br&gt;&lt;br&gt;Mercurial propose, comme Subversion un système de hook pour effectuer des opérations lorsqu'un développeur "push" des modifications sur le serveur désigné comme "central". Un script pour envoyer des mails à chaque push est fourni sur le site, mais n'est pas très souple (script shell basic). &lt;br&gt;&lt;br&gt;Voici un script Python qui offre un peu plus de souplesse:&lt;br&gt;
&lt;pre&gt;#!/usr/bin/python&lt;br&gt;import sys&lt;br&gt;import os&lt;br&gt;import smtplib&lt;br&gt;from email.MIMEText import MIMEText&lt;br&gt;from ConfigParser import ConfigParser&lt;br&gt;from email.Utils import formatdate&lt;br&gt;&lt;br&gt;conffile = os.path.join(os.path.dirname(__file__), 'commithook.conf')&lt;br&gt;config = ConfigParser()&lt;br&gt;config.read(conffile)&lt;br&gt;&lt;br&gt;def command(cmd):&lt;br&gt;    return os.popen(cmd, 'r').read()&lt;br&gt;&lt;br&gt;def send_mail(log, email, subject):&lt;br&gt;    msg = MIMEText(log, 'plain', 'UTF-8')&lt;br&gt;    sender = config.get('configuration', 'sender')&lt;br&gt;    prefix = config.get('configuration', 'prefix')&lt;br&gt;    msg['From'] = sender&lt;br&gt;    msg['To'] = email&lt;br&gt;    msg['Date'] = formatdate(localtime=True)&lt;br&gt;    msg['Subject'] = '%s %s' % (prefix, subject)&lt;br&gt;    server = smtplib.SMTP('localhost')&lt;br&gt;    try:&lt;br&gt;        server.sendmail(sender, [email], msg.as_string())&lt;br&gt;    finally:&lt;br&gt;        server.quit()&lt;br&gt;&lt;br&gt;if __name__ == '__main__':&lt;br&gt;    hg_node = os.getenv('HG_NODE')&lt;br&gt;    subject = command('hg log -r %s | grep "^summary:" | cut -b 14-' % hg_node)&lt;br&gt;    emails = config.get('configuration', 'emails').split(',')&lt;br&gt;    for email in emails:&lt;br&gt;        log = command('hg log -vpr %s' % hg_node)&lt;br&gt;        send_mail(log, email, subject)&lt;br&gt;&lt;/pre&gt;Il est associé à un fichier de configuration qui permet d'indiquer:&lt;br&gt;&lt;ul&gt;&lt;li&gt;le nom de l'expéditeur&lt;/li&gt;&lt;li&gt;le préfix des mails&lt;/li&gt;&lt;li&gt;la liste des emails&lt;/li&gt;&lt;/ul&gt;&lt;br&gt;
exemple de fichier:&lt;br&gt;
&lt;pre&gt;[configuration]&lt;br&gt;sender=tarek_at_ziade.org&lt;br&gt;prefix=[commit]&lt;br&gt;emails=bob_at_gmail.com,tarek_at_ziade.org&lt;br&gt;&lt;/pre&gt;

Ces deux fichiers sont placés dans le répertoire &lt;b&gt;.hg&lt;/b&gt; du repository du serveur, et indiqués dans le fichier &lt;b&gt;hgrc&lt;/b&gt; de ce même répertoire:&lt;br&gt;
&lt;pre&gt;[hooks]&lt;br&gt;incoming = commithook&lt;br&gt;&lt;/pre&gt;Mercurial, pour conclure, est probablement l'un des systèmes de gestion de source les plus souples pour des projets personnels : le repository local peut être à tout moment cloné sur une autre machine, ce qui offre énormément de facilité pour partager son travail versionné, ou mettre en place un système de sauvegarde passif basé sur des push réguliers vers un serveur.&lt;br&gt;&lt;br&gt;Il est probablement équivalent à &lt;a href="http://bazaar-vcs.org/"&gt;Bazaar&lt;/a&gt;, que je n'ai pas encore testé.&lt;br&gt;&lt;br&gt;</content>

  <id>tag:programmation-python.org:sections:blog:2006_12_27_commit-hook-en-python</id>
  <link rel="service.edit" type="application/atom+xml"
        href="http://programmation-python.org/sections/blog/2006_12_27_commit-hook-en-python/atom?2006_12_27_commit-hook-en-python"
        title="Edit Here - commit hook en Python pour mercurial" />
</entry>

  
  
      <entry xmlns="http://purl.org/atom/ns#"
       xmlns:dc="http://purl.org/dc/elements/1.1/">
     
  <title mode="escaped" type="text/html">OpenID, système décentralisé de login</title>
  <link rel="alternate" type="text/html"
        href="http://programmation-python.org/sections/blog/2006_12_19_openid-systeme" />
  <issued>2006-12-19T22:18:11Z</issued>
  <modified>2006-12-19T22:18:11Z</modified>
  <created>2006-12-19T22:07:19Z</created>
  <draft xmlns="http://purl.org/atom-blog/ns#">false</draft>
  <author>
    <name>tarek</name>
  </author>
  
  
    <dc:subject>coding</dc:subject>
  
  
  <summary type="text/html" mode="escaped">Je suis tombé sur ce billet à propos d'OpenID via digg, un système que je ne connaissais pas et qui a un peu plus de 6 mois d'existence. OpenID est un système décentralisé de login développé par LiveJournal. Le principe est simple: le login sur un site est effectué par un appel à un webservice sur un site tiers en charge d'authentifier l'utilisateur. Ce concept n'est pas nouveau (Passeport ...</summary>

  <content type="text/html" mode="escaped"
           xml:space="preserve">&lt;img src="http://en.wikipedia.org/wiki/Image:OpenID_logo.svg"&gt;&lt;br&gt;Je suis tombé sur &lt;a href="http://duggmirror.com/programming/HOW_TO_turn_your_blog_in_to_an_OpenID/"&gt;ce billet à propos d'OpenID via digg&lt;/a&gt;, un système que je ne connaissais pas et qui a un peu plus de 6 mois d'existence. &lt;a href="http://openid.net/"&gt;OpenID&lt;/a&gt; est un système décentralisé de login développé par &lt;a href="http://www.livejournal.com/"&gt;LiveJournal&lt;/a&gt;. Le principe est simple: le login sur un site est effectué par un appel à un webservice sur un site tiers en charge d'authentifier l'utilisateur. &lt;br&gt;&lt;br&gt;Ce concept n'est pas nouveau (Passeport Windows,&amp;nbsp; Passeport Google..) mais ce qui est vraiment intéressant est que le login de l'OpenID est une url, correspondante au site qui sera appelé. En d'autres termes, il est possible de mettre en place son propre système d'identification pour conserver ses mots de passe au frais. Par exemple, si l'OpenID est &lt;i&gt;tarek.ziade.org&lt;/i&gt;, il suffit d'implémenter à cet addresse un service OpenID conforme aux &lt;a href="http://openid.net/specs.bml"&gt;spécifications&lt;/a&gt;.&lt;br&gt;&lt;br&gt;Pour des sites comme &lt;a href="http://afpy.org"&gt;l'afpy&lt;/a&gt;, ou comme ce blog, proposer ce mécanisme d'authentification légère a un grand interêt pour les visiteurs qui souhaitent poster un commentaire, ou dans un forum. (une bibliothèque Python est &lt;a href="http://www.openidenabled.com/openid/libraries/python"&gt;disponible&lt;/a&gt;, et &lt;a href="http://www.openidenabled.com/software/plone"&gt;une implémentation Plone aussi apparament&lt;/a&gt;)&lt;br&gt;&lt;br&gt;Reste à voir si ce standard va prendre, &lt;a href="http://www.google.fr/trends?q=openid&amp;amp;ctab=0&amp;amp;geo=all&amp;amp;date=all"&gt;pour l'instant c'est un peu calme...&lt;/a&gt;&lt;br&gt;</content>

  <id>tag:programmation-python.org:sections:blog:2006_12_19_openid-systeme</id>
  <link rel="service.edit" type="application/atom+xml"
        href="http://programmation-python.org/sections/blog/2006_12_19_openid-systeme/atom?2006_12_19_openid-systeme"
        title="Edit Here - OpenID, système décentralisé de login" />
</entry>

  
  
      <entry xmlns="http://purl.org/atom/ns#"
       xmlns:dc="http://purl.org/dc/elements/1.1/">
     
  <title mode="escaped" type="text/html">MacBook</title>
  <link rel="alternate" type="text/html"
        href="http://programmation-python.org/sections/blog/2006_12_14_macbook" />
  <issued>2006-12-15T01:26:12Z</issued>
  <modified>2006-12-15T01:26:12Z</modified>
  <created>2006-12-14T10:05:23Z</created>
  <draft xmlns="http://purl.org/atom-blog/ns#">false</draft>
  <author>
    <name>tarek</name>
  </author>
  
  
    <dc:subject>misc</dc:subject>
  
  
  <summary type="text/html" mode="escaped">Je lisais le billet de David hier, sur ses essais avec un MacBook. Pour ma part ca fait maintenant deux mois que je suis passé à cette machine, et je suis aussi tout simplement conquis par sa qualité, son faible encombrement et sa maniabilité. Rapport qualité-prix imbattable. Et cette dalle de 13 wide est tellement lumineuse qu'elle vaut largement les 14 ou 15 wide de la plupart des PC.En terme ...</summary>

  <content type="text/html" mode="escaped"
           xml:space="preserve">Je lisais &lt;a href="http://www.biologeek.com/journal/index.php/decouverte-macbook-et-comparaison-mac-os-x-ubuntu"&gt;le billet de David&lt;/a&gt; hier, sur ses essais avec un MacBook. Pour ma part ca fait maintenant deux mois que je suis passé à cette machine, et je suis aussi tout simplement conquis par sa qualité, son faible encombrement et sa maniabilité. Rapport qualité-prix imbattable. Et cette dalle de 13 wide est tellement lumineuse qu'elle vaut largement les 14 ou 15 wide de la plupart des PC.&lt;br&gt;&lt;br&gt;En terme de système, Mac OS X est à mon sens le meilleur système d'exploitation actuel, et je l'ai pris en main sans le connaitre en quelques jours. Voici la liste des logiciels que j'ai installé pour mettre en place un laptop de développement et retrouver tout ce que j'avais sous Ubuntu:&lt;br&gt;&lt;br&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;iTerm&lt;/b&gt;, pour remplacer le terminal de base et avoir un système d'onglets&lt;/li&gt;&lt;li&gt;&lt;b&gt;vim&lt;/b&gt;, qui est devenu mon éditeur de prédilection depuis&lt;/li&gt;&lt;li&gt;&lt;b&gt;adium&lt;/b&gt;, pour jabber et msn&lt;/li&gt;&lt;li&gt;&lt;b&gt;xChat&lt;/b&gt;, pour l'irc&lt;/li&gt;&lt;li&gt;&lt;b&gt;Firefox&lt;/b&gt; et &lt;b&gt;Thunderbird&lt;/b&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;TeXShop&lt;/b&gt;, pour l'édition LaTeX&lt;/li&gt;&lt;li&gt;&lt;b&gt;VLC,&lt;/b&gt; pour la visualisation des vidéos&lt;/li&gt;&lt;li&gt;X11, et du coup: &lt;b&gt;Ooo&lt;/b&gt; et &lt;b&gt;Gimp&lt;/b&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;Google Notifier&lt;/b&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;MenuMeters&lt;/b&gt; : et oui, l'engin est tellement silencieux, qu'il est bon de savoir quand il travaille&lt;/li&gt;&lt;li&gt;&lt;b&gt;Fink&lt;/b&gt; et &lt;b&gt;DarwinPort&lt;/b&gt;, pour installer tous les outils de dev. Par contre ca démultiplie les combinaisons, les PATHs etc.. je m'y perd un peu..&lt;br&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br&gt;&lt;b&gt;
Et vous, quels sont les logiciels dont vous ne pouvez pas vous passer sous Mac ?&lt;/b&gt;&lt;br&gt;&lt;br&gt;Au niveau du terminal, il a fallu le configurer pour que les touches home/end, del, etc, fonctionnent, et définir les locales.&lt;br&gt;&lt;br&gt;&lt;ul&gt;&lt;li&gt;dans HOME/.profile, ajout de &lt;i&gt;export LANG="fr_FR.UTF-8"&lt;/i&gt;&lt;/li&gt;&lt;li&gt;et enfin voici mon HOME/.inputrc:
&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;# inputrc - config file for libreadline&lt;br&gt;# Save as .inputrc (note the leading dot) in your $HOME directory&lt;br&gt;# See readline man page for more information.&lt;br&gt;&lt;br&gt;set meta-flag on&lt;br&gt;&lt;br&gt;# activate 8 bit characters&lt;br&gt;set input-meta on&lt;br&gt;set output-meta on&lt;br&gt;set convert-meta off&lt;br&gt;&lt;br&gt;# suppress bell ringing&lt;br&gt;set bell-style none&lt;br&gt;&lt;br&gt;# case insensitive TAB-completion&lt;br&gt;set completion-ignore-case on&lt;br&gt;&lt;br&gt;# enable Delete/Home/end key in xterm and iTerm&lt;br&gt;"\e[3~": delete-char &lt;br&gt;"\e[1~": beginning-of-line&lt;br&gt;"\e[4~": end-of-line&lt;br&gt;&lt;/pre&gt;Les points négatifs de OS X sont inhérents au modèle commercial:&lt;br&gt;&lt;ul&gt;&lt;li&gt;impossible de regarder une vidéo en plein écran avec QuickTime: il faut acheter la version pro (!!)&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;Le logiciel iWorks, pour faire des slides, est payant, les nagscreens n'oublient pas de le rappeler&lt;/li&gt;&lt;li&gt;Avant l'installation de Ooo, le pack office m'a bien fatigué avec ses nagscreens aussi&lt;/li&gt;&lt;/ul&gt;&lt;br&gt;Ca reste minime, mais c'est dommage pour les slides pilotables avec la télécommande, il faut que j'essaye avec Ooo...&lt;br&gt;&lt;br&gt;En conclusion, je trouve qu'Ubuntu, que j'ai utilisé depuis quasiment ses débuts, n'est pas si loin que ça de Mac OS X en terme d'ergonomie et de qualité, et sera certainement au même&lt;br&gt;niveau d'ici quelques années. De plus, la supériorité d'une solution machine/os issue du même constructeur est de plus en plus relative: les laptops sont maintenant quasiment tous équivalents en terme de composants.&lt;br&gt;&lt;br&gt;</content>

  <id>tag:programmation-python.org:sections:blog:2006_12_14_macbook</id>
  <link rel="service.edit" type="application/atom+xml"
        href="http://programmation-python.org/sections/blog/2006_12_14_macbook/atom?2006_12_14_macbook"
        title="Edit Here - MacBook" />
</entry>

  
  
      <entry xmlns="http://purl.org/atom/ns#"
       xmlns:dc="http://purl.org/dc/elements/1.1/">
     
  <title mode="escaped" type="text/html">Le programme de PyCon 2007</title>
  <link rel="alternate" type="text/html"
        href="http://programmation-python.org/sections/blog/2006_12_12_programme-pycon-2007" />
  <issued>2006-12-12T00:45:41Z</issued>
  <modified>2006-12-12T00:45:41Z</modified>
  <created>2006-12-12T00:35:55Z</created>
  <draft xmlns="http://purl.org/atom-blog/ns#">false</draft>
  <author>
    <name>tarek</name>
  </author>
  
  
    <dc:subject>evenements</dc:subject>
  
  
  <summary type="text/html" mode="escaped">Quel malheur. PyCon 07 est en même temps que le FOSDEM cette année. Il en était de même cet été pour Europython et les RMLL. Le choix va être difficile, surtout que l'Afpy organise cet année une dev room entièrement consacrée à Python (yehaaa). Pour ma part le choix est fait car j'anime un tutorial à PyCon.Les présentationsPycon, c'est plus de 60 talks sur Python cet année :'). Voici celles que ...</summary>

  <content type="text/html" mode="escaped"
           xml:space="preserve">&lt;img src="http://us.pycon.org/common/img/logo-2007-sitemasthead.png" alt="pycon" title="pycon"&gt;&lt;br&gt;&lt;br&gt;Quel malheur. &lt;a href="http://us.pycon.org/TX2007/HomePage"&gt;PyCon 07 &lt;/a&gt;est en même temps que le &lt;a href="http://www.fosdem.org/2007/"&gt;FOSDEM&lt;/a&gt; cette année. Il en était de même cet été pour Europython et les RMLL. Le choix va être difficile, surtout que l'Afpy organise cet année une dev room entièrement consacrée à Python (yehaaa). Pour ma part le choix est fait car &lt;a href="http://tarekziade.wordpress.com/2006/12/02/pycon-2007-tutorial-about-documenting-python-projects/"&gt;j'anime un tutorial à PyCon&lt;/a&gt;.&lt;br&gt;&lt;br&gt;&lt;h2&gt;Les présentations&lt;br&gt;&lt;/h2&gt;&lt;br&gt;Pycon, c'est plus de 60 talks sur Python cet année :'). Voici celles que j'aimerais voir le plus:&lt;br&gt;&lt;br&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;twill, scotch and figleaf &lt;/b&gt;(Titus Brown): outils pour les tests fonctionnels web&lt;/li&gt;&lt;li&gt;&lt;b&gt;the state of Python advocacy &lt;/b&gt;(Jeff Rush): par le responsable PSF de la promotion de Python&lt;/li&gt;&lt;li&gt;&lt;b&gt;testing tool panel&lt;/b&gt; (Grig Gheorghiu): panorama de tous les outils de tests pour Python&lt;/li&gt;&lt;li&gt;&lt;b&gt;the absolute minimum an open source developer must know about intellectual property&lt;/b&gt; (Van Lindberg): tout est dans le titre&lt;/li&gt;&lt;li&gt;&lt;b&gt;Distributing your project with Python eggs&lt;/b&gt; (Stephen Pascoe) : l'art du packaging&lt;/li&gt;&lt;li&gt;&lt;b&gt;Web framework panel &lt;/b&gt;(Titus Brown et al): "confrontation" des core developers des outils web. Toujours intéressant mais très dur à bien ficeler (ie le même panel à Europython qui était un peu désorganisé) On verra..&lt;br&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;Packaging Python apps for Linux Distributions&lt;/b&gt; (Monty Taylor) : beaucoup de choses à apprendre, et par quelqu'un qui sait de quoi il parle&lt;/li&gt;&lt;li&gt;&lt;b&gt;SQLAlchemy&lt;/b&gt; (Mark Ramm-Christensen): il va falloir y arriver tôt&lt;/li&gt;&lt;li&gt;&lt;b&gt;Interactive Parallel and Distributed Computing with IPython&lt;/b&gt; (Brian Granger) : wOOt&lt;/li&gt;&lt;li&gt;&lt;b&gt;Easy creation of interactive tutorials&lt;/b&gt; (Andre Roberge) : demo de Crunchy Python. Ca m'interesse au plus haut point car c'est proche de la documentation agile&lt;/li&gt;&lt;li&gt;&lt;b&gt;Python and VIM &lt;/b&gt;(Sean Reifshneider) : adieu pydev ;)&lt;/li&gt;&lt;li&gt;&lt;b&gt;Unit testing with mocxk objects using PyMock&lt;/b&gt; (Jeff Younker) : j'en ai parlé il y a quelques tickets. A voir/&lt;/li&gt;&lt;li&gt;&lt;b&gt;Software development with Trac&lt;/b&gt; (Matthew Good):&amp;nbsp;  La partie plugins pour le developpement de QA tools et les liaisons avec buildbot.&lt;/li&gt;&lt;/ul&gt;&lt;br&gt;&lt;h2&gt;Projet de reportage Python &lt;br&gt;&lt;/h2&gt;&lt;br&gt;Après le tutoriel je vais arpenter les conférences pour en voir un maximum. Il y aura certainement beaucoup de bloggeurs et filmeurs à Pycon mais probablement pas énormément de francophone. Je lance ici une proposition : si vous êtes passionné de Python et possesseur d'une petite caméra numérique, et prêt à me prêter ce matériel, je propose de faire des comptes rendus par blog et vidéos chaque jour passé à PyCon.&lt;br&gt;&lt;br&gt;</content>

  <id>tag:programmation-python.org:sections:blog:2006_12_12_programme-pycon-2007</id>
  <link rel="service.edit" type="application/atom+xml"
        href="http://programmation-python.org/sections/blog/2006_12_12_programme-pycon-2007/atom?2006_12_12_programme-pycon-2007"
        title="Edit Here - Le programme de PyCon 2007" />
</entry>

  
  
      <entry xmlns="http://purl.org/atom/ns#"
       xmlns:dc="http://purl.org/dc/elements/1.1/">
     
  <title mode="escaped" type="text/html">Le coté obscur de la force</title>
  <link rel="alternate" type="text/html"
        href="http://programmation-python.org/sections/blog/2006_11_29_cote-obscur-force" />
  <issued>2006-11-29T02:37:44Z</issued>
  <modified>2006-11-29T02:37:44Z</modified>
  <created>2006-11-29T02:29:22Z</created>
  <draft xmlns="http://purl.org/atom-blog/ns#">false</draft>
  <author>
    <name>tarek</name>
  </author>
  
  
    <dc:subject>tests</dc:subject>
  
  
  <summary type="text/html" mode="escaped">





EXTERIEUR: PLANETE DAGOBAH -- JOURAvec Yoda accroché sur son dos, Luke grimpe sur les vignes qui entourent les marécages, pour atteindre le laboratoire de statistiques de Dagobah. Il continue sa formation, en pratiquant la programmation dirigée par les tests, en faisant des fakes, des mocks...YODA: Code ! Test ! Oui.  La force d'un programmeur provient de la non-regression. Les ...</summary>

  <content type="text/html" mode="escaped"
           xml:space="preserve">&lt;table width="100%"&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;
&lt;img src="http://upload.wikimedia.org/wikipedia/en/9/9e/Yoda_dagobah.jpg"&gt;
&lt;/td&gt;
&lt;td style="padding: 5px"&gt;
EXTERIEUR: PLANETE DAGOBAH -- JOUR&lt;br&gt;&lt;br&gt;Avec Yoda accroché sur son dos, Luke grimpe sur les vignes qui entourent les marécages, pour atteindre le laboratoire de statistiques de Dagobah. Il continue sa formation, en pratiquant la programmation dirigée par les tests, en faisant des fakes, des mocks...&lt;br&gt;&lt;br&gt;YODA: Code ! Test ! Oui.&amp;nbsp; La force d'un programmeur provient de la non-regression. Les tests arrêter tu ne dois jamais. Le coté obscur de la maintenabilité atteindre tu risques sans les tests. Facile à écrire tes paquets Python sans tests sont. Quand à arrêter les tests tu commences, le coté obscure tu te diriges vers. Ta destinée dominée sera.&lt;br&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;br&gt;LUKE: Mais ce n'est pas mieux sans tests ?&lt;br&gt;&lt;br&gt;YODA: Non... non... non.&amp;nbsp; Plus facile, plus rapide, plus séduisant.&lt;br&gt;&lt;br&gt;LUKE: Alors pourquoi faire des tests ?&lt;br&gt;&lt;br&gt;YODA: Tu sauras. Dans six mois. Quand ton code de corriger tu essayeras.&lt;br&gt;--&lt;br&gt;&lt;br&gt;&lt;a href="http://www.python.org/doc/Humor.html#yoda"&gt;adaptation du post Perl vs Python&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;/td&gt;
&lt;/tr&gt;&lt;tr&gt;&lt;td style="vertical-align: top;"&gt;&lt;br&gt;&lt;/td&gt;&lt;td style="vertical-align: top;"&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;</content>

  <id>tag:programmation-python.org:sections:blog:2006_11_29_cote-obscur-force</id>
  <link rel="service.edit" type="application/atom+xml"
        href="http://programmation-python.org/sections/blog/2006_11_29_cote-obscur-force/atom?2006_11_29_cote-obscur-force"
        title="Edit Here - Le coté obscur de la force" />
</entry>

  
  
      <entry xmlns="http://purl.org/atom/ns#"
       xmlns:dc="http://purl.org/dc/elements/1.1/">
     
  <title mode="escaped" type="text/html">Sortie de PyFAQ 1.0 beta 1</title>
  <link rel="alternate" type="text/html"
        href="http://programmation-python.org/sections/blog/2006_11_18_sortie-pyfaq-1-0-beta-1" />
  <issued>2006-11-17T23:02:59Z</issued>
  <modified>2006-11-17T23:02:59Z</modified>
  <created>2006-11-17T23:01:28Z</created>
  <draft xmlns="http://purl.org/atom-blog/ns#">false</draft>
  <author>
    <name>tarek</name>
  </author>
  
  
    <dc:subject>documentation</dc:subject>
  
  
  <summary type="text/html" mode="escaped">
  

</summary>

  <content type="text/html" mode="escaped"
           xml:space="preserve">&lt;a title="PyFaq" alt="PyFAQ" href="http://effbot.org/pyfaq/"&gt;
  &lt;img src="media/pyfaq.jpg"/&gt;
&lt;/a&gt;
&lt;br/&gt;</content>

  <id>tag:programmation-python.org:sections:blog:2006_11_18_sortie-pyfaq-1-0-beta-1</id>
  <link rel="service.edit" type="application/atom+xml"
        href="http://programmation-python.org/sections/blog/2006_11_18_sortie-pyfaq-1-0-beta-1/atom?2006_11_18_sortie-pyfaq-1-0-beta-1"
        title="Edit Here - Sortie de PyFAQ 1.0 beta 1" />
</entry>

  
  
      <entry xmlns="http://purl.org/atom/ns#"
       xmlns:dc="http://purl.org/dc/elements/1.1/">
     
  <title mode="escaped" type="text/html">Sortie du livre Turbogears</title>
  <link rel="alternate" type="text/html"
        href="http://programmation-python.org/sections/blog/2006_11_09_sortie-du-livre" />
  <issued>2006-11-09T13:44:32Z</issued>
  <modified>2006-11-09T13:44:32Z</modified>
  <created>2006-11-09T13:31:59Z</created>
  <draft xmlns="http://purl.org/atom-blog/ns#">false</draft>
  <author>
    <name>tarek</name>
  </author>
  
  
    <dc:subject>documentation</dc:subject>
  
  
    <dc:subject>livre</dc:subject>
  
  
  <summary type="text/html" mode="escaped">Le livre Rapid web application with Turbogears sort aujourd'hui. Les auteurs ont mis en place un site pour le suivi des errata. Vivement que ce soit dispo sur Amazon.fr..


</summary>

  <content type="text/html" mode="escaped"
           xml:space="preserve">Le livre &lt;a href="http://compoundthinking.com/blog/index.php/2006/11/09/turbogears-book-ships-today/"&gt;Rapid web application with Turbogears&lt;/a&gt; sort aujourd'hui. Les auteurs ont mis 