# articles

feed_id: http://sametmax.com/?p=10371
title: 10 raisons égoïstes pour s’investir dans les préliminaires
uri: 10-raisons-égoïstes-pour-s-investir-dans-les-préliminaires
url: http://sametmax.com/10-raisons-egoistes-pour-sinvestir-dans-les-preliminaires/
content:
<p>Je pense que vous vous êtes TOUS fait rabâcher que les préliminaires c&#8217;est important  qu&#8217;il faut s&#8217;occuper de l&#8217;autre, le sexe c&#8217;est du partage, et gna gna gna, bla bla bla, trolololo lololo lololo.</p>
<p>Le truc c&#8217;est que ce genre d&#8217;arguments ne va parler qu&#8217;à des gens qui sont DÉJÀ de nature à en faire. Prêcher des convertis, c&#8217;est bon pour l&#8217;égo mais ça construit pas grand chose. C&#8217;est pas bon comme Lego. Ok, je => [].</p>
<p>Bref, voici 10 bonnes raisons de faire des préliminaires, parce que ça vous rapporte quelque chose <strong>à vous</strong>.</p>
<h2>1 &#8211; On dure plus longtemps</h2>
<p>Passé une certaine durée d’érection, le corps s&#8217;adapte pour passer en mode endurance. Du coup plus de préliminaires = plus de temps à bander sans trop monter en sauce = plus de temps à bander tout court. </p>
<p>Donc plus de baise. Des performances plus flatteuses. Le temps d&#8217;essayer plus de positions.</p>
<p>Et puis plus d&#8217;opportunité de la faire jouir, puisque ça prend souvent plus de temps que pour nous. Et franchement, qu&#8217;est-ce qu&#8217;il y a de plus sexy qu&#8217;une meuf à qui on est en train de faire prendre son pied ?</p>
<h2>2 &#8211; On chope plus</h2>
<p>Les meufs parlent entre elles. Si vous êtes un bon coup, ça se saura : un secret, c&#8217;est quelque chose que l&#8217;on ne répète qu&#8217;à une personne à la fois. Du coup, rapidement, les copines des copines (un degré de séparation est nécessaire le plus souvent pour en bénéficier) vous voient comme un partenaire sexuel valable.</p>
<h2>3 &#8211; On est en meilleure forme</h2>
<p>Les préliminaire impliquent souvent de tenir des positions qui font travailler vos muscles, votre cœur, votre respiration. Plus il y a de préliminaires, plus votre séance de gym en l&#8217;air devient complète.</p>
<p>Franchement, garder la forme en niquant, y a pire.</p>
<h2>4 &#8211; On a une plus belle peau</h2>
<p>Plus de transpiration et plus de caresses, plus de frictions donc un scrubing + hammam gratos. Votre peau va s&#8217;en trouver toute renouvelée.</p>
<p>Or, scoop, la peau est un facteur hyper important de sex appeal. En fait, avoir une belle peau compense beaucoup d&#8217;autres problèmes. Par exemple, si vous êtes en surpoids avec un superbe épiderme, vous paraissez en bonne santé et donc baisable, si vous avez une super silhouette et une peau de merde, vous donnez autant d&#8217;envie qu&#8217;un lépreux.</p>
<p>Désolé pour les gens à peau difficile, je connais ça, j&#8217;ai été victime de tout un tas de trucs dermatologiquement inesthétiques.</p>
<h2>5 &#8211; Plus de chance de pouvoir choisir où vous venez </h2>
<p>Si vous aimez lui gicler dans la bouche, le cul ou sur les nichons, avoir bien fait monter en température la demoiselle aide beaucoup. Dans le feu de l&#8217;action, on accepte beaucoup plus de choses. La sodomie, douloureuse à froid, peut devenir super excitante quand elle est à fond. Avaler se fera parfois naturellement si vous lui avez léché copieusement la touffe avant. Etc.</p>
<h2>6 &#8211; Plus de sexe avec la même partenaire</h2>
<p>Ça stimule la libido. Et donc si vous avez une fille qui à pas souvent envie, tout d&#8217;un coup, paf, elle répond vachement mieux aux sollicitations. Merci capitaine obvious, tu peux refermer ta braguette maintenant.</p>
<h2>7 &#8211; Plus de jeux pervers</h2>
<p>Ça va avec les deux précédents, mais si vous faites frémir votre partenaire, elle sera forcément plus en confiance pour mettre un costume d&#8217;écolière et s&#8217;empaler sur une tentacule en plastique tout en criant &#8220;Yameru, Kyōju-Sama !&#8221;.</p>
<p>Il faut dire que le cul, ça peut facilement tourner en rond. Du coup, faire des trucs funs et osés en entrée, ça amène un peu de renouveau.</p>
<h2>8 &#8211; Plus de temps pour mettre la capote</h2>
<p>Franchement, c&#8217;est toujours mieux d&#8217;enfiler le bout de plastique quand on a sa langue dans sa chatte que de s&#8217;arrêter pour ça.</p>
<h2>9 &#8211; Plus de temps pour voir si c&#8217;est une vraie rousse</h2>
<p>Je me pose toujours la question.</p>
<h2>10 &#8211; Un passport pour les quickies</h2>
<p>Envie de venir en deux minutes ? Vous pouvez, vous lui avez révolutionné la Sardaigne hier ! C&#8217;est le moment de la monter directement sur la table basse, lui baisser le fut de 20 cm, venir, et repartir comme si de rien n&#8217;était.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=10371&amp;md5=8429c4b801f4f3460ea2991692e2f6a3" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=10380
title: Le potentiel de WAMP, autobahn et crossbar.io
uri: Le-potentiel-de-WAMP-autobahn-et-crossbar-io
url: http://sametmax.com/le-potentiel-de-wamp-autobahn-et-crossbar-io/
content:
<p>Je sais, je sais, je vous fais chier avec <a href="http://sametmax.com/crossbar-le-futur-des-applications-web-python/">crossbar</a> et <a href="http://sametmax.com/un-petit-gout-de-meteor-js-en-python/">autobahn</a>.</p>
<p>Mais ça me tue de ne pas voir plus de monde exploiter cette techno.</p>
<p>Pendant que Max fait la sieste, j&#8217;ai pris mon stylo et j&#8217;ai fait la liste des besoins d&#8217;une app Web actuelle. Quels sont les composants qu&#8217;on utilise presque systématiquement, mais en agrégeant divers bouts de trucs à droite et à gauche ?</p>
<p>Ensuite j&#8217;ai regardé les possibilités des outils WAMP :</p>
<ul>
<li>PUB/SUB et RPC.</li>
<li>Asynchrone.</li>
<li>Gestionnaire de process intégré.</li>
<li>Serveur stand alone qui n&#8217;a pas besoin d&#8217;un proxy pour être en prod.</li>
</ul>
<p>M&#8217;inspirant de cela, et du travail que je suis en train de faire avec l&#8217;équipe de Tavendo pour faire une API flaskesque pour autobahn, j&#8217;ai prototypé une API d&#8217;un framework Web qu&#8217;on pourrait coder au dessus de cette techno.</p>
<p>Voilà ce que ça donne&#8230;</p>
<p>Une API qui mélange flask et nodejs pour le Web</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">app = Application<span style="color: black;">&#40;</span><span style="color: #483d8b;">'YourProjectName'</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Envoyer et recevoir des requêtes HTTP</span>
@app.<span style="color: black;">http</span>.<span style="color: black;">post</span><span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'/form'</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> _<span style="color: black;">&#40;</span>req, res<span style="color: black;">&#41;</span>:
    res.<span style="color: black;">json</span><span style="color: black;">&#40;</span><span style="color: black;">&#123;</span><span style="color: #483d8b;">'data'</span>: <span style="color: #483d8b;">'pouet'</span><span style="color: black;">&#125;</span><span style="color: black;">&#41;</span>
&nbsp;
@app.<span style="color: black;">http</span>.<span style="color: black;">get</span><span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'/user/:id/'</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> _<span style="color: black;">&#40;</span>req, res<span style="color: black;">&#41;</span>:
    res.<span style="color: black;">render</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'index.html'</span>, <span style="color: black;">&#123;</span><span style="color: #483d8b;">'data'</span>: <span style="color: #483d8b;">'pouet'</span><span style="color: black;">&#125;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Servir des fichiers statiques</span>
@app.<span style="color: black;">http</span>.<span style="color: black;">serve</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'uri'</span>, <span style="color: #483d8b;">'/path/to/dir'</span>, <span style="color: black;">&#91;</span>allow_index<span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
&nbsp;
app.<span style="color: black;">run</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Comme c&#8217;est asynchrone, on a de très bonnes perfs. Comme c&#8217;est basé sur Twisted, on a pas besoin d&#8217;un serveur wsgi (gunicorn, uwsgi, etc) ni d&#8217;un proxy (nginx) devant. On peut le mettre en prod tel quel.</p>
<p>Parti de ce principe, on peut ajouter la gestion du PUB/SUB et du RPC pour WAMP :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># Callback attendant l'événement</span>
@app.<span style="color: black;">wamp</span>.<span style="color: black;">event</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'auth.signedin'</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> _<span style="color: black;">&#40;</span>ctx, a, b, c<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">pass</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># déclenchement de l'événément</span>
app.<span style="color: black;">wamp</span>.<span style="color: black;">pub</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'auth.signedin'</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Déclaration du fonnction appelable à distance</span>
@app.<span style="color: black;">wamp</span>.<span style="color: black;">remote</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'auth.signin'</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> _<span style="color: black;">&#40;</span>ctx, a, b, c<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">pass</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># appel de la fonnction</span>
app.<span style="color: black;">wamp</span>.<span style="color: black;">call</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'auth.signin'</span><span style="color: black;">&#41;</span></pre></div></div>

<p>On est souvent perdu quand on fait de l&#8217;asynchrone pour la première fois avec Python car on ne sait pas comment lancer du code après <code>.run()</code>. On peut régler la question proposant des hooks pour les instants clés de l&#8217;app.</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># Callback à lancer quand l'app est prête</span>
@app.<span style="color: black;">on</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'app.ready'</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> _<span style="color: black;">&#40;</span>ctx, args<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">pass</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Signalement que l'app est prête (fait automatiquement en interne</span>
<span style="color: #808080; font-style: italic;"># pour les moments les plus importants)</span>
app.<span style="color: black;">emit</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'app.ready'</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Et tant qu&#8217;on y est, puisqu&#8217;on a une event loop, profitons en pour proposer du CRON intégré à l&#8217;app. C&#8217;est moins chiant à déployer qu&#8217;un script CRON, c&#8217;est cross plateforme, et on a accès facilement à toute sa stack.</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># Lancer du code tous les x temps ou a une date précise</span>
@app.<span style="color: black;">cron</span><span style="color: black;">&#40;</span>every=seconds<span style="color: black;">&#41;</span>
@app.<span style="color: black;">cron</span><span style="color: black;">&#40;</span>every=timedelta, overlap=<span style="color: #008000;">False</span><span style="color: black;">&#41;</span>
@app.<span style="color: black;">cron</span><span style="color: black;">&#40;</span>hour=<span style="color: #ff4500;">7</span>, minute=<span style="color: #ff4500;">30</span>, day_of_week=<span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>
@app.<span style="color: black;">cron</span><span style="color: black;">&#40;</span>when=<span style="color: #dc143c;">datetime</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> _<span style="color: black;">&#40;</span>ctx, args<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">pass</span></pre></div></div>

<p>Pourquoi s&#8217;arrêter là ? Event loop + message passing + safe queues + workers = tasks queues !</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># Créer une file d'attente</span>
queue = @app.<span style="color: black;">queue</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'name'</span>, <span style="color: black;">&#91;</span>workers<span style="color: black;">&#93;</span>, <span style="color: black;">&#91;</span>result_backend<span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Callback appelé par un worker quand il depop ce </span>
<span style="color: #808080; font-style: italic;"># message dans la file</span>
@queue.<span style="color: black;">task</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'encode.video'</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> _<span style="color: black;">&#40;</span>ctx, data<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">pass</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Envoie d'une tache dans la queu</span>
queue.<span style="color: black;">append</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'encode.video'</span>, data<span style="color: black;">&#41;</span></pre></div></div>

<p>Comme on utilise Twisted, on a accès à une chiée de protocoles, et on peut aussi créer les siens. On peut donc imaginer un système de plugins qui rajoute des protocoles supportés :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">app = Application<span style="color: black;">&#40;</span><span style="color: #483d8b;">'YourProjectName'</span><span style="color: black;">&#41;</span>
app.<span style="color: black;">plug</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'lib.ajoutant.sms'</span>, <span style="color: black;">&#91;</span>namespace<span style="color: black;">&#93;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Si on en a beaucoup et que le namespace nous convient :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">app = Application<span style="color: black;">&#40;</span><span style="color: #483d8b;">'YourProjectName'</span>, plugins=<span style="color: black;">&#40;</span><span style="color: #483d8b;">'lib1'</span>, <span style="color: #483d8b;">'lib2'</span>, <span style="color: #483d8b;">'etc'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Exemples de plugins possibles :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># Recevoir et envoyer des SMS (via un service type twilio, une gateway kannel ou</span>
<span style="color: #808080; font-style: italic;"># un modem physique)</span>
@app.<span style="color: black;">sms</span>.<span style="color: black;">receive</span><span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'LOVE <span style="color: #000099; font-weight: bold;">\w</span>+ <span style="color: #000099; font-weight: bold;">\w</span>+'</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> _<span style="color: black;">&#40;</span>ctx, args<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">pass</span>
app.<span style="color: black;">sms</span>.<span style="color: black;">send</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'test'</span>, <span style="color: black;">&#91;</span>contact<span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
&nbsp;
&nbsp;
<span style="color: #808080; font-style: italic;"># Envoyer et recevoir des emails (via un server SMTP ou IMAP)</span>
@app.<span style="color: #dc143c;">email</span>.<span style="color: black;">receive</span><span style="color: black;">&#40;</span>src=r<span style="color: #483d8b;">'.*@sametmax.com'</span>, dest=r<span style="color: #483d8b;">'spam.*@*.'</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> _<span style="color: black;">&#40;</span>ctx, args<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">pass</span>
app.<span style="color: #dc143c;">email</span>.<span style="color: black;">send</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'test'</span>, <span style="color: black;">&#91;</span>contact, title, attachments<span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
&nbsp;
&nbsp;
<span style="color: #808080; font-style: italic;"># techniquement n'importe quel service de message pour lequel on peut écrire</span>
<span style="color: #808080; font-style: italic;"># un backend</span>
@app.<span style="color: black;">tweet</span>.<span style="color: black;">receive</span><span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'Chat'</span><span style="color: black;">&#41;</span>
@app.<span style="color: black;">fb</span>.<span style="color: black;">receive</span><span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'Like'</span><span style="color: black;">&#41;</span>
@app.<span style="color: black;">instagram</span>.<span style="color: black;">receive</span><span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'Bouffe'</span><span style="color: black;">&#41;</span>
@app.<span style="color: black;">irc</span>.<span style="color: black;">message</span><span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'dtc'</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> _<span style="color: black;">&#40;</span>ctx, args<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">pass</span></pre></div></div>

<p>Le problème des apps centrées sur un objet, c&#8217;est qu&#8217;elles ont souvent un design monolithique. Ce n&#8217;est pas un problème du concept d&#8217;app, c&#8217;est juste que les auteurs ont pensé &#8220;point d&#8217;entrée&#8221;, et pas &#8220;élément composable&#8221;.</p>
<p>Si besoin, on doit pouvoir composer une app via plusieurs sous-app :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">app = Application<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
app.<span style="color: black;">embed</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'autre.app'</span><span style="color: black;">&#41;</span></pre></div></div>

<p>ou</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">app = Application<span style="color: black;">&#40;</span>embed=<span style="color: black;">&#91;</span><span style="color: #483d8b;">'app1'</span>, <span style="color: #483d8b;">'app2'</span>, <span style="color: #483d8b;">'app3'</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Il faut des hooks pour overrider la configuration, mais vous avez compris le principe.</p>
<p>Un autre problème avec les plateformes comme NodeJS, c&#8217;est qu&#8217;il est difficile d&#8217;utiliser plusieurs coeurs. C&#8217;est une des raisons du succès de Go.</p>
<p>Or, Crossbar encourage la division en plusieurs process qui communiquent entre eux (un peu comme les channels). Créons aussi une API pour ça :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">p1 = app.<span style="color: black;">process</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
p2 = app.<span style="color: black;">process</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Déclarer et appeler une procédure dans process 1</span>
@p1.<span style="color: black;">wamp</span>.<span style="color: black;">remote</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'auth.signin'</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> _<span style="color: black;">&#40;</span>ctx, args<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">pass</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Déclarer et appeler une procédure dans process 2</span>
@p2.<span style="color: black;">wamp</span>.<span style="color: black;">event</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'auth.signedin'</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> _<span style="color: black;">&#40;</span>ctx, args<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">pass</span></pre></div></div>

<p>Ainsi on profite enfin de plusieurs CPU. La même chose en plus facile à changer:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># Déclarer et appeler une procédure</span>
@app.<span style="color: black;">wamp</span>.<span style="color: black;">remote</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'auth.signin'</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> _<span style="color: black;">&#40;</span>ctx, args<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">pass</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Déclarer et appeler une procédure</span>
@app.<span style="color: black;">wamp</span>.<span style="color: black;">event</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'auth.signedin'</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> _<span style="color: black;">&#40;</span>ctx, args<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">pass</span>
&nbsp;
app.<span style="color: black;">processes</span><span style="color: black;">&#40;</span><span style="color: black;">&#123;</span>
    <span style="color: #ff4500;">1</span>: <span style="color: black;">&#91;</span><span style="color: #483d8b;">'wamp.remote:auth.signin'</span><span style="color: black;">&#93;</span>
    <span style="color: #ff4500;">2</span>: <span style="color: black;">&#91;</span><span style="color: #483d8b;">'wamp.event:auth.signedin'</span><span style="color: black;">&#93;</span>
<span style="color: black;">&#125;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>En bonus, on fait la nique au GIL.</p>
<p>Mieux, on peut bouger ses process sur plusieurs machines :</p>
<p>Machine 1 (routeur):</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">router = Application<span style="color: black;">&#40;</span>endpoint=<span style="color: #483d8b;">&quot;0.0.0.0:8080&quot;</span><span style="color: black;">&#41;</span>
router.<span style="color: black;">run</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Machine 2 (authentification):</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># IP du router</span>
auth = Application<span style="color: black;">&#40;</span><span style="color: #483d8b;">'auth'</span>, connect_to=<span style="color: #483d8b;">&quot;182.64.1.15:8080&quot;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Nommage automatique en fonction du nom de la fonction</span>
<span style="color: #808080; font-style: italic;"># et de l'app, avec possibilité d'annuler ou overrider le prefix.</span>
<span style="color: #808080; font-style: italic;"># Ici du coup la fonction s'appellera en RPC via 'auth.signin'</span>
@auth.<span style="color: black;">wamp</span>.<span style="color: black;">remote</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> signin<span style="color: black;">&#40;</span>ctx, args<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">pass</span>
&nbsp;
auth.<span style="color: black;">run</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Machine 3 (API REST):</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">web = Application<span style="color: black;">&#40;</span><span style="color: #483d8b;">'site'</span>, connect_to=<span style="color: #483d8b;">&quot;182.64.1.15:8080&quot;</span><span style="color: black;">&#41;</span>
&nbsp;
@web.<span style="color: black;">http</span>.<span style="color: black;">post</span><span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'api/auth/'</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> _<span style="color: black;">&#40;</span>req, res<span style="color: black;">&#41;</span>:
    <span style="color: #dc143c;">user</span> = <span style="color: #ff7700;font-weight:bold;">yield</span> res.<span style="color: black;">wamp</span>.<span style="color: black;">call</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'auth.signin'</span>,
                               req.<span style="color: black;">POST</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">'username'</span><span style="color: black;">&#93;</span>,
                               req.<span style="color: black;">POST</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">'password'</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">*</span>
    <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #dc143c;">user</span>
        <span style="color: #dc143c;">user</span> = <span style="color: #ff7700;font-weight:bold;">yield</span> res.<span style="color: black;">wamp</span>.<span style="color: black;">pub</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'auth.signedin'</span>, <span style="color: #dc143c;">user</span>.<span style="color: black;">userid</span><span style="color: black;">&#41;</span>
        res.<span style="color: black;">json</span><span style="color: black;">&#40;</span><span style="color: black;">&#123;</span><span style="color: #483d8b;">'token'</span>: <span style="color: #dc143c;">user</span>.<span style="color: #dc143c;">token</span><span style="color: black;">&#125;</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">else</span>:
        res.<span style="color: black;">json</span><span style="color: black;">&#40;</span><span style="color: black;">&#123;</span><span style="color: #483d8b;">'error'</span>: <span style="color: #483d8b;">'nope'</span><span style="color: black;">&#125;</span><span style="color: black;">&#41;</span>
&nbsp;
&nbsp;
@web.<span style="color: black;">http</span>.<span style="color: black;">get</span><span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'api/stuff/'</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> _<span style="color: black;">&#40;</span>req, res<span style="color: black;">&#41;</span>:
    res.<span style="color: black;">json</span><span style="color: black;">&#40;</span>get_stuff<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
@web.<span style="color: black;">http</span>.<span style="color: black;">serve</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'uri'</span>, <span style="color: #483d8b;">'/path/to/dir'</span>, <span style="color: black;">&#91;</span>allow_index<span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
&nbsp;
web.<span style="color: black;">run</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Et vous savez le plus beau dans tout ça ? En Python on a plein de libs qui sont encore bloquantes. En théorie on ne peut pas les utiliser dans les apps asynchrones. Quand on a toute sa logique métiers dans des classes d&#8217;ORM, c&#8217;est balot. Mais pas ici ! On met un process avec tous ces appels bloquants, et on les appelle depuis des process non bloquant en RPC de manière asynchrone. Pif, paf, pouf, problème isolé.</p>
<p>Après, libre à son imagination de rajouter des fonctionnalités de confort&#8230;</p>
<p>Callback qui sera appelé seulement x fois :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># Déclarer et appeler une procédure</span>
@p1.<span style="color: black;">wamp</span>.<span style="color: black;">event</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'auth.signedin'</span>, options=<span style="color: black;">&#123;</span><span style="color: #483d8b;">'limit_calls'</span>: x<span style="color: black;">&#125;</span> <span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> _<span style="color: black;">&#40;</span>ctx, args<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">pass</span></pre></div></div>

<p>Raccourcis pour les opérations courantes :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># Recevoir et envoyer un événement</span>
@app.<span style="color: black;">sub</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'auth.signin'</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> _<span style="color: black;">&#40;</span>ctx, <span style="color: #66cc66;">*</span>args<span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;"># ctx.pub</span>
@app.<span style="color: black;">pub</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'auth.signedin'</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Déclarer et appeler une procédure</span>
@app.<span style="color: black;">proc</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'auth.signedin'</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> _<span style="color: black;">&#40;</span>ctx, args<span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;"># ctx.call</span>
app.<span style="color: black;">rpc</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Comme je vous l&#8217;avais expliqué, crossbar peut gérer le cycle de vie de services externes à votre application au démarrage. Autant exposer cette API programativement :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">@app.<span style="color: black;">service</span><span style="color: black;">&#40;</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">'/urs/bin/nodejs'</span>, <span style="color: #483d8b;">'script.js'</span><span style="color: black;">&#93;</span>, <span style="color: black;">&#91;</span><span style="color: #dc143c;">user</span><span style="color: black;">&#93;</span>, <span style="color: black;">&#91;</span>group<span style="color: black;">&#93;</span><span style="color: black;">&#41;</span></pre></div></div>

<p><code>.run()</code>, c&#8217;est cool, mais si on veut changer des options via la ligne de commande, faut se taper tout le boulot alors que ça pourrait très bien se générer automatiquement :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">@app.<span style="color: black;">cmd_run</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Et si vous faites : <code>python sites.py --debug=true --endpoint=0.0.0.0:5252</code>, ça le prend automatiquement en compte. Y a pas de raison de se faire chier.</p>
<p>En parlant de générer automatiquement des trucs, le fichiers de configs pour les services externes sur lesquels on peut avoir envie de brancher notre app, c&#8217;est toujours galère. Autant fournir un exemple de base qui est sûr de toujours marcher, généré avec les paramètres de notre app :</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">python site.py template centos:nginx
python site.py template ubuntu:upstart
python site.py template bsd:systemd <span style="color: #666666; font-style: italic;"># :D</span></pre></div></div>

<p>On peut partir très loin dans le délire &#8220;battery included&#8221;. Typiquement, on peut fournir des services externes nous même puisque crossbar nous le propose, et coder des versions moins bien, mais compatibles (et suffisantes pour les petits sites), de projets toujours utilses :</p>
<ul>
<li>cache (compatible redis)</li>
<li>live settings (compatible etcd) mais avec en prime un event wamp propagé à chaque</li>
<p>  changement de valeur</p>
<li>build (compatible, heu, j&#8217;en sais rien) qui s&#8217;occupe en tâche de fond de surveiller le >système de fichier et lancer les compilations, les minifications, les copies, les tests unittaires, etc.</li
<li>logging centralisé (compatible sentry).</li>
<li>Un bridge WAMP/REST qui permet d&#8217;envoyer et recevoir des events WAMP sur votre app Django ou flask en utilisant HTTP.</li>
</ul>
<p>On plug tout ça a une admin Web.</p>
<p>J&#8217;espère que je vous ai donné maintenant l&#8217;envie de vous plonger un peu plus dans cette techno, et peut être coder quelque chose avec.</p>
<p>Il n&#8217;y a plus d&#8217;excuses pour ne pas avoir de framework web next gen, ultime de la mort qui tue en Python. A part le fait qu&#8217;on soit des feignasses.</p>
<p>Ah, merde, on est foutus.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=10380&amp;md5=3eea15c9f696fc0f66b07cf105a749c1" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=10392
title: Télécharger une page du blog en PDF
uri: Télécharger-une-page-du-blog-en-PDF
url: http://sametmax.com/telecharger-une-page-du-blog-en-pdf/
content:
<p>On m&#8217;a <a href="http://sametmax.com/le-potentiel-de-wamp-autobahn-et-crossbar-io/#comment-40031">demandé</a> de rendre possible téléchargement des articles en PDF.</p>
<p>Je suis paresseux, donc plutôt que d&#8217;installer un plugin, j&#8217;ai juste fait un lien vers un service externe en haut à droite de toutes les pages.</p>
<p>Si vous cliquez, ça vous génère le PDF pour la page complète, et ça marche pour toutes les URL, pas uniquement les articles.</p>
<p>De rien.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=10392&amp;md5=e45b3b95cad9fbaa3dcac5b80957d55d" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=10398
title: Écrivez à l’arc, envoyez des sioux
uri: Écrivez-à-l-arc-envoyez-des-sioux
url: http://sametmax.com/ecrivez-a-larc-envoyez-des-sioux/
content:
<p>Les gens derrière le développement de Python sont extraordinaires : Python existe depuis 1990, cela fait donc plus de 20 ans qu&#8217;il est là, à évoluer, sans cesse.</p>
<p>Et cela a un coût. Un langage qui permet à Youtube, Dropbox et Instagram de tourner, ça doit douiller non ?</p>
<div id="attachment_10403" class="wp-caption aligncenter" style="width: 510px"><a href="media/4d6bba91.tumblr_n684vge7NJ1r539hzo1_500.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2014/06/tumblr_n684vge7NJ1r539hzo1_500.jpg"><img src="media/4d6bba91.tumblr_n684vge7NJ1r539hzo1_500.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2014/06/tumblr_n684vge7NJ1r539hzo1_500.jpg" alt="Photo de personnes déguisés en télétubies fumant et buvant" title="Youtube, Dropbox et instagram consomment toujours beaucoup" width="500" height="373" class="size-full wp-image-10403" /></a><p class="wp-caption-text">Youtube, Dropbox et instagram consomment toujours beaucoup</p></div>
<p>Et bien, la partie fun, c&#8217;est que le plus gros du boulot est fait par des volontaires. En fait, le budget total alloué par la Python Software Fundation pour <strong>payer</strong> des dev à travailler sur le langage est <a href="http://pyfound.blogspot.com/2012/01/psf-grants-over-37000-to-python.html">moins de 30 000 euros par an</a>. Même pas le salaire d&#8217;un ingé sénior. Parce qu&#8217;ils n&#8217;ont pas de pognon.</p>
<p>Alors, on peut se gargariser que, trop cool, la communauté Python contribue à mort et ça coute pas cher. Mais moi ce que je vois, ce sont des centaines de mecs qui bossent super dur, gratos, pour qu&#8217;on puisse en bénéficier d&#8217;un côté, et de l&#8217;autre, une fondation qui n&#8217;a pas de thune pour aller au bout de sa mission.</p>
<p>La honte, c&#8217;est bien entendu que des boites comme Google, Apple ou Sony, qui sont blindées, ne renvoient pas l’ascenseur alors qu&#8217;ils utilisent le langage en interne.</p>
<div id="attachment_10400" class="wp-caption aligncenter" style="width: 510px"><a href="media/8f7c1e9b.tumblr_n572kwK67E1r539hzo1_500.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2014/06/tumblr_n572kwK67E1r539hzo1_500.jpg"><img src="media/8f7c1e9b.tumblr_n572kwK67E1r539hzo1_500.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2014/06/tumblr_n572kwK67E1r539hzo1_500.jpg" alt="Photo d&#039;un homme assi sur un fauteuil luxueux avec un catana et une peau de tigre" title="Ouai c&#039;est Google. Ouai. Ouai. Nan rien à foutre." width="500" height="500" class="size-full wp-image-10400" /></a><p class="wp-caption-text">Ouai c&#039;est Google. Ouai. Ouai. Nan rien à foutre.</p></div>
<p>Mais ça, on peut rien y faire dans la seconde.</p>
<p>Ce qu&#8217;on peut faire tout de suite, en revanche, c&#8217;est filer 10€ &#8211; 100€, nous, en tant que dev, ou boite. Si vous utilisez professionnellement Python, je pense que sur toute une vie, c&#8217;est raisonnable.</p>
<p>Je hais la culpabilisation, donc l&#8217;idée n&#8217;est pas de vous dire &#8220;si vous ne donnez pas vous êtes des connards&#8221;. Simplement je donne régulièrement aux projets que j&#8217;utilise : VLC, Ubuntu, LibreOffice, etc. Et Le blog fait la promotion de Python, alors il est juste que je vous invite à envoyer des sous à la PSF.</p>
<div id="attachment_10399" class="wp-caption aligncenter" style="width: 510px"><a href="media/370288cf.tumblr_n55aed3WRL1r539hzo1_500.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2014/06/tumblr_n55aed3WRL1r539hzo1_500.jpg"><img src="media/370288cf.tumblr_n55aed3WRL1r539hzo1_500.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2014/06/tumblr_n55aed3WRL1r539hzo1_500.jpg" alt="Photo d&#039;un chat mençant un chien avec un couteau" title="Par contre le chantage ne me gène pas. Si vous ne donnez pas, je posterai une photo de chaton par jour dans la rubrique cul de sam et max. Ouai, nan, c&#039;est plus dur pour moi que pour vous en fait." width="500" height="427" class="size-full wp-image-10399" /></a><p class="wp-caption-text">Par contre le chantage ne me gène pas. Si vous ne donnez pas, je posterai une photo de chaton par jour dans la rubrique cul de sam et max. Ouai, nan, c&#039;est plus dur pour moi que pour vous en fait.</p></div>
<p>Ce n&#8217;est pas une question d&#8217;être une bonne personne. C&#8217;est juste un bon moyen d&#8217;aider au dev d&#8217;un outil qu&#8217;on aime, pour en bénéficier demain.</p>
<p style="text-align:center;  margin:3em">
<a style="font-size:3em;" href="https://www.python.org/psf/donations/">Faites pêter l&#8217;oseille</a>
  </p>
<p>Dommage, ils n&#8217;acceptent pas les bitcoins.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=10398&amp;md5=ab455c5aa7df535daf2230b1eeecfc7c" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=10418
title: Deferred, Future et Promise : le pourquoi, le comment, et quand est-ce qu’on mange
uri: Deferred-Future-et-Promise-le-pourquoi-le-comment-et-quand-est-ce
url: http://sametmax.com/deferred-future-et-promise-le-pourquoi-le-comment-et-quand-est-ce-quon-mange/
content:
<p>Si vous avez plongé dans le monde de la programmation asynchrone non bloquante, vous avez du vous heurter aux <a href="http://sametmax.com/quest-ce-quun-callback/">callbacks</a>. Si ce n&#8217;est pas le cas, aller lire l&#8217;article, et faites vos armes sur jQuery, je vais m&#8217;en servir en exemple.</p>
<p>Signalement de rigueur que l&#8217;article est long :</p>

<!-- iframe plugin v:2.3 - wordpress.org/extend/plugins/iframe/ -->
<iframe width="560" height="315" src="//www.youtube.com/embed/E8b4xYbEugo" frameborder="0" scrolling="no" class="iframe-class"></iframe>
<p>Un callback, ça va.</p>
<p>Deux callbacks, pour un seul appel, ça commence à être chiant, mais c&#8217;est compréhensible.</p>
<p>Quand les callbacks appellent eux aussi des callbacks, ça donne des codes imbitables :</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">$<span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
  $.<span style="color: #660066;">post</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'/auth/token'</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>token<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
    saveToken<span style="color: #009900;">&#40;</span>token<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    $.<span style="color: #660066;">get</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'/sessions/last'</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>session<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
      <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>session.<span style="color: #660066;">device</span> <span style="color: #339933;">!=</span> currentDevice<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
        $.<span style="color: #660066;">get</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'/session/ '</span> <span style="color: #339933;">+</span> session.<span style="color: #660066;">id</span> <span style="color: #339933;">+</span> <span style="color: #3366CC;">'/context'</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>context<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
          loadContext<span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
            startApp<span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
              initUi<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
            <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span>
          <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#125;</span>
        <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#125;</span>
      <span style="color: #000066; font-weight: bold;">else</span> <span style="color: #009900;">&#123;</span>
        startApp<span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
          initUi<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
        <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span>
      <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Il y a pire que de lire ce code : le modifier ! Retirez un bloc, pour voir. Oh, et histoire de vous faire partager l&#8217;expérience complète, j&#8217;ai volontairement déplacé l&#8217;indentation d&#8217;une parenthèse et de deux brackets.</p>
<p>Or les codes asynchrones ont besoin de callback afin d’enchainer certaines opérations dans le bon ordre, sinon on ne peut pas récupérer le résultat d&#8217;une fonction et l&#8217;utiliser dans une autre, puisqu&#8217;on ne sait pas quand l&#8217;opération se termine.</p>
<p>Dans notre exemple, <code>$.post</code> et <code>$.get</code> font des requêtes POST et GET, et comme on ne sait pas quand le serveur va répondre, il faut mettre un callback pour gérer la réponse quand elle arrive. C&#8217;est plus performant que de bloquer jusqu&#8217;à ce que la première requête soit terminée car pendant ce temps, notre programme peut faire autre chose. Mais c&#8217;est aussi super relou à écrire et comprendre.</p>
<p>Entre en jeu les promesses (promises). Ou les deferred. Ou les futures.</p>
<p>Typiquement, on retrouve des deferreds dans <a href="https://twistedmatrix.com/trac/">Twisted</a>, des promises pour <a href="http://api.jquery.com/jquery.ajax/">l&#8217;AJAX avec jQuery,</a> des futures pour <a href="http://docs.python.org/3.4/library/asyncio-protocol.html">asyncio</a>&#8230; Mais il y en a un peu partout de nos jours, et une lib peut utiliser plusieurs de ces concepts.</p>
<p>En fait c&#8217;est la même chose, un nom différent donné au même concept, par des gens qui l&#8217;ont réinventé dans leur coin. Les puristes vous diront qu&#8217;il y a des différences dans l&#8217;implémentation, ou alors que la promesse est l&#8217;interface tandis que le deferred est l&#8217;objet retourné, bla, bla, bla.</p>
<p>Fuck it, on va considérer que c&#8217;est tout pareil.</p>
<p>Les promesses sont une des manières de rendre un code asynchrone plus facile à gérer. On dit : ce groupe de fonctions doit s&#8217;exécuter dans un ordre car elles sont dépendantes les unes des autres.</p>
<p>Il y a d&#8217;autres moyens de gérer le problème de l&#8217;asynchrone: des événements, des queues, etc. L&#8217;avantage des promesses c&#8217;est que c&#8217;est assez simple, et ça marche là où on utilisait des callbacks avant, donc on a pu les rajouter aux libs qui étaient blindés de callbacks.</p>
<h2>Le principe</h2>
<p>La promesse est un moyen de dire que certaines fonctions, bien que non bloquantes et asynchrones, sont liées entre elles, et doivent s&#8217;exécuter les unes à la suite des autres. Cela permet de donner un ordre d&#8217;exécution à un groupe de fonctions, et surtout, que chaque fonction puisse accéder au résultat de la fonction précédente. Tout ceci sans bloquer le reste du système asynchrone.</p>
<p>En résumé, <strong>cela donne un gout de programmation synchrone, à quelque chose qui ne l&#8217;est pas.</strong></p>
<p>Cela se passe ainsi :</p>
<ul>
<li>La fonction asynchrone retourne un objet immédiatement : la promesse.</li>
<li>On ne passe pas de callback à la fonction. On rajoute un callback à la promesse.</li>
<li>Le callback prend en paramètre le résultat de la fonction asynchrone.</li>
<li>Le callback retourne le résultat de son traitement.</li>
<li>On peut rajouter autant de callbacks qu&#8217;on veut à la promesse, chacun devant accepter le résultat du callback précédent et retourner son propre résultat.</li>
<li>Si un des callbacks retourne une promesse, elle est fusionnée avec la promesse initiale, et c&#8217;est son résultat que le prochain callback va récupérer</li>
</ul>
<p>Voilà un exemple :</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #006600; font-style: italic;">// $.get est asynchrone. On a pas le résultat tout de suite, mais en attendant</span>
<span style="color: #006600; font-style: italic;">// on a une promesse tout de suite.</span>
<span style="color: #003366; font-weight: bold;">var</span> $promesse <span style="color: #339933;">=</span> $.<span style="color: #660066;">get</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'/truc/machin'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #006600; font-style: italic;">// premier callback. Il sera appelé quand $.get aura récupéré son</span>
<span style="color: #006600; font-style: italic;">// résultat</span>
$promesse.<span style="color: #660066;">then</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>resultat<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
  <span style="color: #006600; font-style: italic;">// faire un truc avec le résultat</span>
  <span style="color: #006600; font-style: italic;">// puis on retourne le nouveau résultat</span>
  <span style="color: #000066; font-weight: bold;">return</span> nouveau_resultat<span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #006600; font-style: italic;">// deuxième callback. Il sera appelé quand le premier callback</span>
<span style="color: #006600; font-style: italic;">// aura retourné son résultat.</span>
$promesse.<span style="color: #660066;">then</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>nouveau_resultat<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
  <span style="color: #006600; font-style: italic;">// faire un truc</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Notez bien que c&#8217;est TRES différent de ça (en Python):</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">resultat = request.<span style="color: black;">get</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'/truc/marchin'</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> function<span style="color: black;">&#40;</span>resultat<span style="color: black;">&#41;</span>:
  <span style="color: #808080; font-style: italic;"># faire un truc</span>
  <span style="color: #ff7700;font-weight:bold;">return</span> nouveau_resultat
nouveau_resultat = function<span style="color: black;">&#40;</span>resultat<span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> autre_function<span style="color: black;">&#40;</span>nouveau_resultat<span style="color: black;">&#41;</span>:
  <span style="color: #808080; font-style: italic;"># faire un truc</span>
autre_function<span style="color: black;">&#40;</span>nouveau_resultat<span style="color: black;">&#41;</span></pre></div></div>

<p>En Python, le code est bloquant par défaut. Ça va marcher, mais pendant que le code attend la réponse du serveur, votre ordinateur est en pause et ne travaille pas.</p>
<h2>Un plus beau code</h2>
<p>On se retrouve avec un code asynchrone, mais qui s&#8217;exécute dans l&#8217;ordre de lecture. Et comme on peut chainer les <code>then()</code> et donc ne pas réécrire <code>$promesse</code> à chaque fois, on obtient quelque chose de beaucoup plus lisible :</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">$.<span style="color: #660066;">get</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'/truc/machin'</span><span style="color: #009900;">&#41;</span>
.<span style="color: #660066;">then</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>resultat<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
  <span style="color: #006600; font-style: italic;">// faire un truc</span>
  <span style="color: #000066; font-weight: bold;">return</span> nouveau_resultat<span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span>
.<span style="color: #660066;">then</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>nouveau_resultat<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
  <span style="color: #006600; font-style: italic;">// faire un truc</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Si on reprend notre premier exemple, ça donne ça :</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">$<span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
&nbsp;
<span style="color: #006600; font-style: italic;">// create new token</span>
$.<span style="color: #660066;">post</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'/auth/token'</span><span style="color: #009900;">&#41;</span>
&nbsp;
<span style="color: #006600; font-style: italic;">// then save token and get last session</span>
.<span style="color: #660066;">then</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>token<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
  saveToken<span style="color: #009900;">&#40;</span>token<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #000066; font-weight: bold;">return</span> $.<span style="color: #660066;">get</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'/sessions/last'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span>
&nbsp;
<span style="color: #006600; font-style: italic;">// then init session</span>
.<span style="color: #660066;">then</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>session<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
  <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>session.<span style="color: #660066;">device</span> <span style="color: #339933;">!=</span> currentDevice<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
&nbsp;
    $.<span style="color: #660066;">get</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'/session/ '</span> <span style="color: #339933;">+</span> session.<span style="color: #660066;">id</span> <span style="color: #339933;">+</span> <span style="color: #3366CC;">'/context'</span><span style="color: #009900;">&#41;</span>
    .<span style="color: #660066;">then</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>context<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
      loadContext<span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
        startApp<span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
          initUi<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
        <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span>
      <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span>
&nbsp;
  <span style="color: #009900;">&#125;</span>
  <span style="color: #000066; font-weight: bold;">else</span> <span style="color: #009900;">&#123;</span>
    startApp<span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
      initUi<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span>
&nbsp;
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Tout ça s’exécute de manière non bloquante (d&#8217;autres fonctions ailleurs dans le programme peuvent s&#8217;exécuter pendant qu&#8217;on attend la réponse du serveur), mais dans l&#8217;ordre de lecture, donc on comprend bien ce qui se passe. Si on veut retirer un bloc, c&#8217;est beaucoup plus facile.</p>
<h2>Comment ça marche à l&#8217;intérieur ?</h2>
<p>Histoire d&#8217;avoir une idée de comment une promise marche, on va faire une implémentation, simpliste et naïve, mais compréhensible, d&#8217;une promesse en Python. Pour rendre l&#8217;API un peu sympa,je vais utiliser <a href="http://sametmax.com/comprendre-les-decorateurs-python-pas-a-pas-partie-1/">les décorateurs.</a></p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">class</span> Promise:
&nbsp;
    <span style="color: #808080; font-style: italic;"># La promesse contient une liste de callbacks, donc une liste de fonctions.</span>
    <span style="color: #808080; font-style: italic;"># Pas le résultat des fonctions, mais bien les fonctions elles mêmes,</span>
    <span style="color: #808080; font-style: italic;"># puisque les fonctions sont manipulables en Python.</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>.<span style="color: black;">callbacks</span> = <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Point d'entrée pour ajouter un callback à la promesse</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> then<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, callback<span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>.<span style="color: black;">callbacks</span>.<span style="color: black;">append</span><span style="color: black;">&#40;</span>callback<span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Cette méthode est celle qui sera appelée par le code asynchrone</span>
    <span style="color: #808080; font-style: italic;"># quand il reçoit son résultat.</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> resolve<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, resultat<span style="color: black;">&#41;</span>:
&nbsp;
        <span style="color: #808080; font-style: italic;"># Ici, on obtient le résultat du code asycnhrone, donc on boucle</span>
        <span style="color: #808080; font-style: italic;"># sur les callbacks pour les appeler</span>
        <span style="color: #ff7700;font-weight:bold;">while</span> <span style="color: #008000;">self</span>.<span style="color: black;">callbacks</span>:
            <span style="color: #808080; font-style: italic;"># On retire le premier callback de la liste, et on l'appelle</span>
            <span style="color: #808080; font-style: italic;"># avec le résultat</span>
            resultat = <span style="color: #008000;">self</span>.<span style="color: black;">callbacks</span>.<span style="color: black;">pop</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span><span style="color: black;">&#40;</span>resultat<span style="color: black;">&#41;</span>
&nbsp;
            <span style="color: #808080; font-style: italic;"># Si le resultat est une promesse, on dit à cette nouvelle promesse</span>
            <span style="color: #808080; font-style: italic;"># de nous rappeler quand a elle a reçu ses résultats à elle avant</span>
            <span style="color: #808080; font-style: italic;"># d'aller le reste de nos callbacks a nous : on fusionne les deux</span>
            <span style="color: #808080; font-style: italic;"># promesses :</span>
            <span style="color: #808080; font-style: italic;"># Promesse 1</span>
            <span style="color: #808080; font-style: italic;">#  - callback1</span>
            <span style="color: #808080; font-style: italic;">#  - callback2</span>
            <span style="color: #808080; font-style: italic;">#  - Promesse 2</span>
            <span style="color: #808080; font-style: italic;">#      * callback 1</span>
            <span style="color: #808080; font-style: italic;">#      * callback 2</span>
            <span style="color: #808080; font-style: italic;">#  - callback 3</span>
            <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">isinstance</span><span style="color: black;">&#40;</span>resultat, Promise<span style="color: black;">&#41;</span>:
                resultat.<span style="color: black;">then</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">resolve</span><span style="color: black;">&#41;</span>
                <span style="color: #ff7700;font-weight:bold;">break</span></pre></div></div>

<p>Maintenant, créons un code asynchrone:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">from</span> <span style="color: #dc143c;">threading</span> <span style="color: #ff7700;font-weight:bold;">import</span> Timer
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> func1<span style="color: black;">&#40;</span>v1<span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;"># On dit complètement artificiellement d'afficher le résultat</span>
    <span style="color: #808080; font-style: italic;"># de la fonction dans 3 secondes, sans bloquer histoire d'avoir</span>
    <span style="color: #808080; font-style: italic;"># un peu de nonbloquitude dans notre code et justifier l'asynchrone.</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> callback1<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>v1<span style="color: black;">&#41;</span>
    t = Timer<span style="color: black;">&#40;</span><span style="color: #ff4500;">3</span>, callback1<span style="color: black;">&#41;</span>
    t.<span style="color: black;">start</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> func2<span style="color: black;">&#40;</span>v2<span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;"># Le même, mais pour 2 secondes</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> callback2<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>v2<span style="color: black;">&#41;</span>
    t = Timer<span style="color: black;">&#40;</span><span style="color: #ff4500;">2</span>, callback2<span style="color: black;">&#41;</span>
    t.<span style="color: black;">start</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Deux fonctions normales</span>
<span style="color: #ff7700;font-weight:bold;">def</span> func3<span style="color: black;">&#40;</span>v3<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>v3<span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> func4<span style="color: black;">&#40;</span>v4<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>v4<span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Et si on les enchaines...</span>
<span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Je commence'</span><span style="color: black;">&#41;</span>
func1<span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Juste après'</span><span style="color: black;">&#41;</span>
func2<span style="color: black;">&#40;</span><span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span>
func3<span style="color: black;">&#40;</span><span style="color: #ff4500;">3</span><span style="color: black;">&#41;</span>
func4<span style="color: black;">&#40;</span><span style="color: #ff4500;">4</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># ... le résultat est bien désordonné :</span>
&nbsp;
<span style="color: #808080; font-style: italic;">## Je commence</span>
<span style="color: #808080; font-style: italic;">## Juste après</span>
<span style="color: #808080; font-style: italic;">## 3</span>
<span style="color: #808080; font-style: italic;">## 4</span>
<span style="color: #808080; font-style: italic;">## 2</span>
<span style="color: #808080; font-style: italic;">## 1</span></pre></div></div>

<p>Parfois c&#8217;est ce que l&#8217;on veut, que les choses s’exécutent dans le désordre, sans bloquer.</p>
<p>Mais quand on a des fonctions qui dépendent les unes des autres, au milieu d&#8217;un code asynchrone, on veut qu&#8217;elles se transmettent le résultat les unes aux autres au bon moment. Pour cela, utilisons notre promesse :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">from</span> <span style="color: #dc143c;">threading</span> <span style="color: #ff7700;font-weight:bold;">import</span> Timer
&nbsp;
&nbsp;
<span style="color: #808080; font-style: italic;"># La mise en place de promesses suppose que le code </span>
<span style="color: #808080; font-style: italic;"># écrit en fasse explicitement usage. Notre code est</span>
<span style="color: #808080; font-style: italic;"># définitivement lié à cette manière de faire.</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> func1<span style="color: black;">&#40;</span>v1<span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;"># Notre fonction doit créer la promesse et la retourner</span>
    p = Promise<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> callback1<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>v1<span style="color: black;">&#41;</span>
        <span style="color: #808080; font-style: italic;"># Dans le callback, elle doit dire quand la promesse est tenue</span>
        p.<span style="color: black;">resolve</span><span style="color: black;">&#40;</span>v1<span style="color: black;">&#41;</span>
    t = Timer<span style="color: black;">&#40;</span><span style="color: #ff4500;">3</span>, callback1<span style="color: black;">&#41;</span>
    t.<span style="color: black;">start</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> p
&nbsp;
<span style="color: #808080; font-style: italic;"># On lance la première fonction.</span>
<span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Je commence'</span><span style="color: black;">&#41;</span>
promise = func1<span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Juste après'</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># On ajoute des callbacks à notre promesse.</span>
&nbsp;
@promise.<span style="color: black;">then</span>
<span style="color: #ff7700;font-weight:bold;">def</span> func2<span style="color: black;">&#40;</span>v2<span style="color: black;">&#41;</span>:
    p = Promise<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> callback2<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
        <span style="color: #808080; font-style: italic;"># Pour justifier l’enchainement des fonctions, on fait en sorte que</span>
        <span style="color: #808080; font-style: italic;"># chaque fonction attend le résultat de la précédente, et</span>
        <span style="color: #808080; font-style: italic;"># l'incrémente de 1.</span>
        <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>v2 + <span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>
        p.<span style="color: black;">resolve</span><span style="color: black;">&#40;</span>v2 + <span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>
    t = Timer<span style="color: black;">&#40;</span><span style="color: #ff4500;">2</span>, callback2<span style="color: black;">&#41;</span>
    t.<span style="color: black;">start</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    <span style="color: #808080; font-style: italic;"># Ce callback retourne lui-même une promesse, qui sera fusionnée</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> p
&nbsp;
<span style="color: #808080; font-style: italic;"># Ces callbacks ne retournent pas de promesses, et seront chainés</span>
<span style="color: #808080; font-style: italic;"># normalement</span>
@promise.<span style="color: black;">then</span>
<span style="color: #ff7700;font-weight:bold;">def</span> func3<span style="color: black;">&#40;</span>v3<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>v3 + <span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> v3 + <span style="color: #ff4500;">1</span>
&nbsp;
@promise.<span style="color: black;">then</span>
<span style="color: #ff7700;font-weight:bold;">def</span> func4<span style="color: black;">&#40;</span>v4<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>v4 + <span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Nos fonctions s'exécutent dans le bon ordre, mais bien de manière</span>
<span style="color: #808080; font-style: italic;"># asynchrone par rapport au reste du programme.</span>
&nbsp;
<span style="color: #808080; font-style: italic;">## Je commence</span>
<span style="color: #808080; font-style: italic;">## Juste après</span>
<span style="color: #808080; font-style: italic;">## 1</span>
<span style="color: #808080; font-style: italic;">## 2</span>
<span style="color: #808080; font-style: italic;">## 3</span>
<span style="color: #808080; font-style: italic;">## 4</span></pre></div></div>

<p>Notez bien :</p>
<ul>
<li>Le résultat &#8220;1&#8243; n&#8217;apparait que trois secondes après &#8220;Juste après&#8221;. Les fonctions sont donc bien non bloquantes.</li>
<li>Le resultat &#8220;2&#8243; apparait deux secondes après &#8220;1&#8243;: c&#8217;est aussi asynchrone, MAIS, n&#8217;est lancé que quand la première fonction a terminé son travail.</li>
<li>La deuxième fonction retourne une promesse, qui est fusionnée: tous ses callbacks vont s&#8217;exécuter en file avant que <code>func3</code> soit lancé. </li>
</ul>
<p>Évidement, n&#8217;utilisez pas cette implémentation de promise à la maison, c&#8217;est pédagogique. Ça ne gère pas les erreurs, ni le cas où le callback est enregistré après l&#8217;arrivée du résultat, et tout un tas d&#8217;autres cas tordus.</p>
<h2>Syntaxe alternative</h2>
<p>En Python, beaucoup de frameworks ont une approche plus agréable pour gérer les promesses à grand coup de <a href="http://sametmax.com/comment-utiliser-yield-et-les-generateurs-en-python/">yield</a>. Twisted fait ça avec son <code>@inlineCallback</code>, <code>asyncio</code> avec <code>@coroutine</code>. C&#8217;est juste du sucre syntaxique pour vous rendre la vie plus facile.</p>
<p>Il s&#8217;agit de transformer une fonction en générateur, et à chaque fois qu&#8217;on appelle <code>yield</code> sur une promesse, elle est fusionnée avec la précédente. Ça donne presque l&#8217;impression d&#8217;écrire un code bloquant normal :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># un appel de fonction asyncrone typique de twisted</span>
@inlineCallback
<span style="color: #ff7700;font-weight:bold;">def</span> une_fonction<span style="color: black;">&#40;</span>data<span style="color: black;">&#41;</span>:
  data = <span style="color: #ff7700;font-weight:bold;">yield</span> func1<span style="color: black;">&#40;</span>data<span style="color: black;">&#41;</span>
  data = <span style="color: #ff7700;font-weight:bold;">yield</span> func2<span style="color: black;">&#40;</span>data<span style="color: black;">&#41;</span>
  data = <span style="color: #ff7700;font-weight:bold;">yield</span> func3<span style="color: black;">&#40;</span>data<span style="color: black;">&#41;</span>
&nbsp;
une_fonction<span style="color: black;">&#40;</span>truc<span style="color: black;">&#41;</span></pre></div></div>

<p>Les fonctions 1, 2 et 3 vont ainsi être appelées de manière asynchrone par rapport au reste du programme, mais bien s’enchainer les unes à la suite des autres.</p>
<p>Ouai, tout ce bordel parce que l&#8217;asynchrone, c&#8217;est dur, donc on essaye de le faire ressembler à du code synchrone, qui lui est facile.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=10418&amp;md5=adf0568366c6b0f00340cf1accd3fc68" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=10433
title: assert “а” == “a” # lol
uri: assert-а-a-lol
url: http://sametmax.com/assert-%d0%b0-a-lol/
content:
<p>Python 3, le bonheur d&#8217;avoir UTF8 comme encoding par défaut !</p>
<p>En plus, ça ajoute un petit potentiel de lulz.</p>
<p>Par exemple, ceci marche très bien :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #dc143c;">test</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Youpi'</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Youpi'</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Et ceci&#8230;</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #dc143c;">test</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Arg'</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Arg'</span><span style="color: black;">&#41;</span></pre></div></div>

<p>&#8230; provoque une syntaxe error !</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">  File <span style="color: #483d8b;">&quot;&lt;stdin&gt;&quot;</span>, line <span style="color: #ff4500;">2</span>
       <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Arg'</span><span style="color: black;">&#41;</span>
    ^
<span style="color: #008000;">SyntaxError</span>: invalid character <span style="color: #ff7700;font-weight:bold;">in</span> identifier</pre></div></div>

<p>La raison est que la première ligne print(&#8216;Arg&#8217;) contient le caractère unicode U+0020, qui est un espace inimprimable, mais pas le même que l&#8217;ascii :)</p>
<p>Bon, vous allez-me dire, on pouvait déjà mélanger les tabs et les espaces, s&#8217;amuser avec les espaces insécables, ou simplement déclarer manuellement l&#8217;encoding et faire pareil&#8230;</p>
<p>Allons plus loin. Saviez-vous qu&#8217;on pouvait utiliser des caractères non-ASCII <strong>dans les identifiants</strong> en Python 3 ?</p>
<p>Ceci est donc parfaitement valide :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">éôà = <span style="color: #ff4500;">1</span></pre></div></div>

<p>Ce qui invite bien entendu a des choses tout à fait amusantes comme :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> аttention<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'!'</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #66cc66;">&gt;&gt;&gt;</span> аttention<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">!</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> attention<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
Traceback <span style="color: black;">&#40;</span>most recent call last<span style="color: black;">&#41;</span>:
  File <span style="color: #483d8b;">&quot;&lt;stdin&gt;&quot;</span>, line <span style="color: #ff4500;">1</span>, <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #66cc66;">&lt;</span>module<span style="color: #66cc66;">&gt;</span>
<span style="color: #008000;">NameError</span>: name <span style="color: #483d8b;">'attention'</span> <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #ff7700;font-weight:bold;">not</span> defined</pre></div></div>

<p>En effet, j&#8217;ai utilisé le caractère &#8220;а&#8221; cyrilique comme première lettre, et non le &#8220;a&#8221; ASCII. Ils n&#8217;ont pas le même code :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #008000;">ord</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;а&quot;</span><span style="color: black;">&#41;</span>, <span style="color: #008000;">ord</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;a&quot;</span><span style="color: black;">&#41;</span>
<span style="color: black;">&#40;</span><span style="color: #ff4500;">1072</span>, <span style="color: #ff4500;">97</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #483d8b;">&quot;а&quot;</span> == <span style="color: #483d8b;">&quot;a&quot;</span>
<span style="color: #008000;">False</span></pre></div></div>

<p>Quand j&#8217;étais au lycée, une bonne blague qu&#8217;on faisait aux profs était de faire une capture d&#8217;écran du bureau de leur ordi, la mettre en fond d&#8217;écran, virer les icônes et régler la barrer des tâches pour se cacher automatiquement. Ils pensaient que leur machine était freezée, et un reboot ne changeait rien. Des heures à s&#8217;arracher les cheveux.</p>
<p>Avec les identifiants unicodes je pense qu&#8217;on peut retrouver cette merveilleuse créativité avec ses collègues.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=10433&amp;md5=e35a47ba5a1bb5cc1a1857a2f4294990" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=10438
title: La protection CSRF de Django et les requêtes Ajax
uri: La-protection-CSRF-de-Django-et-les-requêtes-Ajax
url: http://sametmax.com/la-protection-csrf-de-django-et-les-requetes-ajax/
content:
<p>La protection contre les <a href="https://fr.wikipedia.org/wiki/CSRF">attaques CSRF</a> est dans le top 10 des erreurs les plus chiantes en Django, main dans la main avec les fichiers statiques qui ne marchent pas, les URL qui ne matchent pas et les CBV qui nheuuuu, juste pas.</p>
<p>Une fois qu&#8217;on a compris le principe, ça va pour la prog normal, mais un jour on a besoin de faire un POST en Ajax, et on se retrouve avec une erreur invisible. Après avoir dégainé Firebug, on comprend qu&#8217;on a une 403 forbidden, et votre cerveau finit (la durée galérienne est plus ou moins longue selon les profiles, les heures de sommeil et les phases de la lune) par réaliser qu&#8217;on n&#8217;a pas envoyé le token CSRF. Merde.</p>
<p>C&#8217;est là que généralement les gens sortent du <code>@csrf_exempt</code>, ou carrément, en finissent avec cette solution radicale :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">MIDDLEWARE_CLASSES = <span style="color: black;">&#40;</span>
    <span style="color: #483d8b;">'django.middleware.gzip.GZipMiddleware'</span>,
    <span style="color: #483d8b;">'django.middleware.common.CommonMiddleware'</span>,
    <span style="color: #483d8b;">'django.contrib.sessions.middleware.SessionMiddleware'</span>,
    <span style="color: #483d8b;">'django.middleware.locale.LocaleMiddleware'</span>,
    <span style="color: #808080; font-style: italic;"># 'django.middleware.csrf.CsrfViewMiddleware',</span>
    <span style="color: #483d8b;">'django.contrib.auth.middleware.AuthenticationMiddleware'</span>,
    <span style="color: #483d8b;">'django.contrib.messages.middleware.MessageMiddleware'</span>,
<span style="color: black;">&#41;</span></pre></div></div>

<p>Mais c&#8217;est quand même dommage d&#8217;en arriver là alors qu&#8217;on peut le faire proprement.</p>
<p>D&#8217;abord, le token est sauvegardé dans un cookie. Il faut donc le récupérer.</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #006600; font-style: italic;">// ue petite fonction pour récupérer la valeur d'un cookie,</span>
<span style="color: #006600; font-style: italic;">// puisque bien entendu, comme toutes les APIS javascripts,</span>
<span style="color: #006600; font-style: italic;">// les choses qu'on fait le plus souvent ne sont pas incluses</span>
<span style="color: #006600; font-style: italic;">// en natif. Oui je suis aigri.</span>
<span style="color: #003366; font-weight: bold;">function</span> getCookie<span style="color: #009900;">&#40;</span><span style="color: #000066;">name</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>document.<span style="color: #660066;">cookie</span> <span style="color: #339933;">&amp;&amp;</span> document.<span style="color: #660066;">cookie</span> <span style="color: #339933;">!=</span> <span style="color: #3366CC;">''</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #003366; font-weight: bold;">var</span> cookies <span style="color: #339933;">=</span> document.<span style="color: #660066;">cookie</span>.<span style="color: #660066;">split</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">';'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000066; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">var</span> i <span style="color: #339933;">=</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">;</span> i <span style="color: #339933;">&lt;</span> cookies.<span style="color: #660066;">length</span><span style="color: #339933;">;</span> i<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            <span style="color: #003366; font-weight: bold;">var</span> cookie <span style="color: #339933;">=</span> jQuery.<span style="color: #660066;">trim</span><span style="color: #009900;">&#40;</span>cookies<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>cookie.<span style="color: #660066;">substring</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">0</span><span style="color: #339933;">,</span> <span style="color: #000066;">name</span>.<span style="color: #660066;">length</span> <span style="color: #339933;">+</span> <span style="color: #CC0000;">1</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">==</span> <span style="color: #009900;">&#40;</span><span style="color: #000066;">name</span> <span style="color: #339933;">+</span> <span style="color: #3366CC;">'='</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
                <span style="color: #000066; font-weight: bold;">return</span> decodeURIComponent<span style="color: #009900;">&#40;</span>cookie.<span style="color: #660066;">substring</span><span style="color: #009900;">&#40;</span><span style="color: #000066;">name</span>.<span style="color: #660066;">length</span> <span style="color: #339933;">+</span> <span style="color: #CC0000;">1</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                <span style="color: #000066; font-weight: bold;">break</span><span style="color: #339933;">;</span>
            <span style="color: #009900;">&#125;</span>
        <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Sinon, pour les fainéants, il y a y a un <a href="https://github.com/carhartl/jquery-cookie">plugin jquery</a> qui permet de faire <code>$.cookie('nom')</code>.</p>
<p>Ensuite, on attache cette valeur en header avec toutes les requêtes POST. Comme ça, plus besoin de l&#8217;inclure manuellement, on peut faire ses requêtes sans y penser.</p>
<p>Avec jQuery :</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">$.<span style="color: #660066;">ajaxSetup</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#123;</span>
    <span style="color: #006600; font-style: italic;">// fonction appelée avant d'envoyer une requête AJAX</span>
    beforeSend<span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>xhr<span style="color: #339933;">,</span> settings<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
         <span style="color: #006600; font-style: italic;">// on ajoute le header que si la requête est pour le site en cours</span>
         <span style="color: #006600; font-style: italic;">// (URL relative) et est de type POST</span>
         <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!/^</span>https<span style="color: #339933;">?:</span>.<span style="color: #339933;">*/</span>.<span style="color: #660066;">test</span><span style="color: #009900;">&#40;</span>settings.<span style="color: #660066;">url</span><span style="color: #009900;">&#41;</span>  <span style="color: #339933;">&amp;&amp;</span> settings.<span style="color: #660066;">type</span> <span style="color: #339933;">==</span> <span style="color: #3366CC;">&quot;POST&quot;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
             <span style="color: #006600; font-style: italic;">// attachement du token dans le header</span>
             xhr.<span style="color: #660066;">setRequestHeader</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;X-CSRFToken&quot;</span><span style="color: #339933;">,</span>  getCookie<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'csrftoken'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
         <span style="color: #009900;">&#125;</span>
     <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Avec AngularJs :</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #006600; font-style: italic;">// interception de la configuration du provider HTTP</span>
<span style="color: #006600; font-style: italic;">// qui possède un mécanisme déjà tout prêt pour ça</span>
votre_app.<span style="color: #660066;">config</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>$httpProvider<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    $httpProvider.<span style="color: #660066;">defaults</span>.<span style="color: #660066;">xsrfCookieName</span> <span style="color: #339933;">=</span> <span style="color: #3366CC;">'csrftoken'</span><span style="color: #339933;">;</span>
    $httpProvider.<span style="color: #660066;">defaults</span>.<span style="color: #660066;">xsrfHeaderName</span> <span style="color: #339933;">=</span> <span style="color: #3366CC;">'X-CSRFToken'</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Attention, si l&#8217;app n&#8217;est pas servie par Django (template statique avec uniquement des appels Ajax), il faut faire au moins un GET avant de faire son premier POST afin d&#8217;obtenir le cookie.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=10438&amp;md5=322eb319a567675b1d6fb1e8aed01281" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=10445
title: Comment trouve-t-on des clients en freelance ?
uri: Comment-trouve-t-on-des-clients-en-freelance
url: http://sametmax.com/comment-trouve-t-on-des-clients-en-freelance/
content:
<p>Ça faisait longtemps que je n&#8217;avais pas publié le courrier des lecteurs. Voici un mail que j&#8217;ai reçu et la réponse envoyée (avec une ou deux corrections).</p>
<blockquote><p>Comment trouve-t-on des clients en freelance ? Vous avez surfé sur le réseau du job précédent, ou la demande est telle qu&#8217;il suffit de s&#8217;inscrire en tant que dev python dans les pages jaunes ?</p></blockquote>
<p><em>Hello,</p>
<p>Je depop les emails datant de mars en juin :)</p>
<p>Pour trouver des clients en tant que freelance :</p>
<p>- utiliser le carnet d&#8217;adresse de sa boîte précédente. Ça suppose un travail régulier à garder le contact avec les interlocuteurs qu&#8217;on a avec les clients externes, demander les numéros/emails directes, les postes, etc. L&#8217;important est de bien être transparent et de ne pas essayer de choper des contrats qui auraient été donnés à son ancienne boîte. Il faut être un complément sur les projets en cours, ou prendre les projets que les autres ne prennent pas. Ça ne peut pas se faire a posteriori, ça se prépare pendant son séjour dans la boîte, et ça suppose une démarche semi-commerciale une fois qu&#8217;on est dehors.</p>
<p>- aller aux événements/lieux sociaux tech. Tout ce qui est conférences (type la cantine, NUMA), salons (type PyConFR, Djangocong), soirées à thème (on peut les organiser soi-même), petit dej entrepreneur (type open coffee), associations (type hackerspace, fablab). Faire sa review, découvrir de nouvelles technos et les partager avec les autres (proposer une présentation, un tuto, un workshop, etc), ça créé des liens.</p>
<p>- créer un site, avec son CV, un tweeter, et scanner régulièrement la recherche tweeter pour des demandes. Il y en a une chiée.</p>
<p>- faire toutes les semaines un tour des annonces sur les dizaines de sites d&#8217;offre d&#8217;emploi. Même si une offre ne demande pas un freelance, proposer quand même. Même si l&#8217;offre est à l&#8217;étranger (proposer de bouger, ou télétravail). On finit toujours pas trouver un truc, mais même quand on en trouve pas, ça fait des contacts. Google est ton ami. Les RSS aussi. Tu es dev, dev un script qui ratisse large et récupère pour toi toutes ces infos et en fait la synthèse.</p>
<p>- prétendre qu&#8217;on est freelance depuis longtemps. Demander à des amis de mentir pour soit en ce faisant passé pour un référent dans un boîte et donner son numéro. Je suis très sérieux.</p>
<p>- ton compte github peut être un bon CV, le mettre en avant.</p>
<p>- on est pas obligé de quitter sa boîte pour être freelance. Le status auto entrepreneur est cumulable avec un travail à plein temps (prendre des missions courtes et travailler le we) ou mi-temps (pour se lancer). On est pas obliger de faire le grand saut d&#8217;un coup.</p>
<p>@+</p>
<p>Sam</em></p>
<p>On entend souvent dire &#8220;construisez votre réseau&#8221;, &#8220;faites marcher votre réseau&#8221;, mais la réalité c&#8217;est que la plupart des gens n&#8217;en ont pas et ne savent pas comment en construire un. C&#8217;est pour ça qu&#8217;il faut attaquer sur deux tableaux : les annonces en ligne (assez facile, contrats moins sympas, mais permet de ternir à court terme et boucher les trous) et les événements sociaux (plus dur, mais meilleurs résultats sur le long terme).</p>
<p>Si vous arrivez à travailler pour une niche (informatique pour pharmaceutique, gestion de projet industriel automobile, booking, etc), il est beaucoup plus facile de démarcher ensuite dans cette niche. N&#8217;hésitez donc pas au début à vous spécialiser dedans.</p>
<p>Ça fait écho à l&#8217;article <a href="http://sametmax.com/ou-trouver-un-job-ou-une-mission-python-django/">Où trouver un Job ou une mission Python / Django ?</a>, même si il faudrait que je fasse un dossier complet là dessus un jour avec :</p>
<ul>
<li>Où et comment chercher les annonces.</li>
<li>Comment créer un CV.</li>
<li>Comment établir des contacts commerciaux aux événements sociaux.</li>
<li>Contacter un client potentiel/</li>
<li>Comment mener le premier entretient avec un client, puis le second.</li>
<li>Comment conclure avec sa proposition commerciale</li>
<li>Comment faire sa veille techno et rendre son profile toujours plus intéressant.</li>
<li>Comment se mettre en avant en général et donner envie en tant que dev.</li>
<li>Comment établir un devis, facturer, combien, pour quoi, etc.</li>
<li>Comment recruter un dev.</li>
<li>Comment gérer un dev.</li>
<li>Comment gérer un projet : côté dev et côté client.</li>
</ul>
<p>Comme d&#8217;hab, tout ceci est prévu pour après 2038, un jeudi, vers 16h47.</p>
<p>Mais ça serait intéressant, surtout que sur le Web ont dit à tout le monde de jouer franc jeu, d&#8217;être un bon garçon, etc, alors que clairement c&#8217;est un jeu de dupe et vous serez gagnant en trichant. Pas en bossant pas, attention, faut fournir le taff pour lequel on est payé, mais &#8220;soyez-vous même&#8221; est le conseil le plus débile que le cinéma et votre maman vous ait donné quand il s&#8217;agit de maximiser ses chances de plaire (dans le job et dans d&#8217;autres domaines).</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=10445&amp;md5=07c1866cb583b5a7f1076cf47b267137" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=10455
title: Les graves problèmes de la vie en Thaïlande
uri: Les-graves-problèmes-de-la-vie-en-Thaïlande
url: http://sametmax.com/les-graves-problemes-de-la-vie-en-thailande/
content:
<p><em>Quelques morceaux choisis de ces dernières semaines. Les > sont des monologues, les &#8211; sont des dialogues.</em></p>
<p>> ce soir une amie de ma cop veut tourner une scène meuf/meuf pour son pigeon, je suis chargé de trouver une meuf partante, j&#8217;ai un budget de 1500 TBH payé par elle et j&#8217;ai le droit de me faire sucer par la meuf<br />
> puis je dois filmer<br />
> elle se fait 20 000 TBH en vendant sa scène lesbienne<br />
> faut que je trouve une bouffeuse de minou<br />
> je me demande si c&#8217;est pas mieux de passer un coup de fil à requin<br />
> elle a fait ses preuves<br />
> t&#8217;as son num?</p>
<hr />
<p>- Hi, I need to change my mirror glass and wheel<br />
- Ok, 600 BHT (14€).<br />
- I&#8217;ll be back tomorrow  ?<br />
- No. Ready. 20 minutes.</p>
<hr />
<p>> les thais dans les restos, c&#8217;est toujours leur premier jour. Ils peuvent avoir travaillé 10 ans, ça change rien. Ils vont se coucher, le lendemain, tu as un thai tout neuf.</p>
<hr />
<p>- Bon alors tu vas tout droit, vers la colline, et quand tu atteins un scouter rouge garé, tu prends à gauche.<br />
- &#8230;</p>
<hr />
<p>> Bon les photos du DJ qui mixe avec sa bite, on les mets dans &#8220;musique&#8221; ou dans &#8220;amateur&#8221; ?</p>
<hr />
<p>- Non, ma nouvelle meuf m&#8217;a racheté à l&#8217;ancienne.<br />
- T&#8217;a racheté ?<br />
- Oui, elle lui a donné un paquet de drogue pour ne plus me voir.<br />
- Ta nouvelle meuf c&#8217;est pas celle en taule pour trafique de drogue et du coup tu dois garder ses clebs ?<br />
- Yep. Son avocat me demande 350 000 BHT pour la faire sortir ou elle reste 10 ans.</p>
<hr />
<p>> Donc la grosse, elle se pointe dès qu&#8217;elle voit les photos du bbq sur facebook, elle bouffe tout, elle se met la race avec notre vodka, et une fois qu&#8217;elle voit que sa copine se fait chauffer dans la piscine, elle l&#8217;embarque et se casse.<br />
> Et on la connaissais même pas.</p>
<hr />
<p>- Le mec de ce resto, il fait de la haute cuisine française.<br />
- Mais comment il s&#8217;en sort ?<br />
- L&#8217;astuce, c&#8217;est qu&#8217;il a deux cartes. Une pour les connards de touristes. Dès qu&#8217;il voit un australien ou un russe, il lui sort le menu frite, hamburger et bière. Et quand les compatriotes arrivent, il nous file le coq au vin et la pana-cota maison.</p>
<hr />
<p>17h > Bon parlons des choses importantes : ou-est-ce qu&#8217;on bouffe ? Fuji ? Batcave ? 101 ? BBQ ? Marché ? Da Moreno ? Buffet sushi ? Samsha ? Suédois ? Coffee mania ? Halal ?<br />
20h> Bon, ça fait 3 heures qu&#8217;on débat, je tranche. Batcave. Ou peut être 101. Quoique je me ferais bien une pizza. C&#8217;est con que le mec des buritos ait fermé. L&#8217;indien c&#8217;est trop lourd, et au 101 ils ont une choucroute&#8230;</p>
<hr />
<p>> Ils ont ouvert un Hooters en centre ville ? C&#8217;est idiot, c&#8217;est comme tenir un stand de pêche aux canards en face de Disneyland.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=10455&amp;md5=23c767a98c963afd2991bb33033fa7b6" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=10476
title: CLOC it
uri: CLOC-it
url: http://sametmax.com/cloc-it/
content:
<p>CLOC est un petit prog perl qui retourne des stats sur le code qu&#8217;on a dans un dossier.</p>
<p>Sur ubuntu, ça s&#8217;installe avec un <code>sudo apt-get install cloc</code>, et un <code>cloc /home/sam/work</code> plus tard, on obtient un rapport sur le nombre de fichiers / lignes de code par langage :</p>
<pre>
---------------------------------------------------------
Language            files      blank    comment      code
---------------------------------------------------------
HTML                10585     392921      49870   2909814
Javascript           1497     118180     220836    656645
Python               3132     104173     129888    517995
CSS                   399      23324      10117    164944
XML                  2860       7435      16148     89942
Java                  194       7364      34214     30960
XSLT                   83       3902       1992     25842
Bourne Shell           91       1998       2511     16263
C                      48       2824       4020     11810
C/C++ Header          167       4256       7775     10015
SQL                    59       1640       1347      8961
LESS                   50       1371       1308      5884
C++                    35       1244        782      5772
make                   41        806        283      3691
QML                    56        413        906      2458
Visualforce Page       17        175         22      1253
Bourne Again Shell     17        109        145       883
m4                      2         99         22       707
SASS                   20        127         41       596
ActionScript            1         71        121       553
DOS Batch               8         63         19       359
DTD                     5        159        280       355
PHP                     2         58        250       315
D                       2         32         -2       171
CMake                   4         28         11       124
Ruby                    5         37          9       120
CoffeeScript            1         30         10        95
Teamcenter def          1          0          0        91
XSD                     3         10          0        78
YAML                    5          7          0        49
Arduino Sketch          1         17         27        41
IDL                     2         12          0        38
MATLAB                  1         21         62        35
C Shell                 1          8          6        18
Visual Basic            1          0          0        18
ASP.Net                 1          4          0         9
---------------------------------------------------------
SUM:                19397     672918     483020   4466904
---------------------------------------------------------
</pre>
<p>Pour le HTML, on a compris que j&#8217;étais un dev très orienté Web. Mais, horreur, coderai-je plus de Javascript que de Python ?</p>
<p>Non, je vous rassure. C&#8217;est juste que mon dossier de travail contient moult documentation Web dumpées pour être consultées hors ligne, de nombreuses libs JS dupliquées (j&#8217;aime pas les CDN) et aucun de mes virtualenv. </p>
<p>Rien que la doc d&#8217;angular :</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">find</span> <span style="color: #660033;">-iname</span> <span style="color: #ff0000;">&quot;*.js&quot;</span>  <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">grep</span> angular <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">wc</span>
<span style="color: #000000;">632</span></pre></div></div>

<p>On notera qu&#8217;il y a deux fois plus de fichiers Python (3132 c&#8217;est pas énorme quand on y pense) que de fichiers JS, mais un peu moins de lignes malgré tout, ce qui reflète bien la tendance à tasser beaucoup de code dans un seul gros fichier en JS.</p>
<p>2860 fichiers XML ? Bordel, mais d&#8217;où viennent-ils ?</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">find</span> <span style="color: #660033;">-iname</span> <span style="color: #ff0000;">&quot;*.xml&quot;</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">grep</span> docker <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">wc</span>
<span style="color: #000000;">2790</span></pre></div></div>

<p>Ah, ok.</p>
<p>Je serais curieux de savoir ce que ça donne pour un dev scientifique, un sys admin, un débutant, un chevronné, etc.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=10476&amp;md5=0a259e199cab84c95179e7c5fcc52470" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=10520
title: Ma boîte à outils Python, mise à jour
uri: Ma-boîte-à-outils-Python-mise-à-jour
url: http://sametmax.com/ma-boite-a-outils-python-mise-a-jour/
content:
<p>Il y a bien longtemps je vous avais parlé de <a href="http://sametmax.com/sept-petites-libs-qui-changent-la-vie-dun-dev-python/">7 libs Python </a> vraiment chouettes, puis quelques articles pour vous signaler des remplaçants, ici et là.</p>
<p>Comme je ne m&#8217;attends pas à ce que vous suiviez le blog article par article, voici une petit synthèse, la conclusion de l&#8217;évolution de ma boîte à outils Python.</p>
<h2>D&#8217;abord, ce qui n&#8217;a pas changé</h2>
<p><a href="http://sametmax.com/debugger-en-python-les-bases-de-pdb/">Ipdb</a>, est toujours de la partie. Je m&#8217;essaye à <a href="https://pypi.python.org/pypi/pudb">pudb</a> de temps à autre, mais vraiment pour casser l&#8217;habitude. Ipdb reste la référence pour tout debugger. C&#8217;est simple, c&#8217;est puissant, c&#8217;est fantastique.</p>
<p><a href="https://github.com/jaraco/path.py">path.py</a>, inébranlable remplacement de os.path et shutil, malgré l&#8217;intégration de <a href="https://docs.python.org/3/library/pathlib.html?highlight=pathlib#module-pathlib">pathlib</a> à python 3.4 qui est loin d&#8217;être aussi bon. J&#8217;ai même fait quelques contributions sur le projet, notamment l&#8217;écriture de fichier &#8220;inplace&#8221;.</p>
<p><a href="http://docs.python-requests.org/">requests</a>, la fantastique lib HTTP, qui n&#8217;évolue plus beaucoup, car qui a besoin d&#8217;améliorer la perfection ? On regrettera l&#8217;absence de version asynchrone, bien que certains projets alternatifs, moins bons, s&#8217;y collent.</p>
<p><a href="http://bottlepy.org/">bottle</a>, toujours pour bricoler des sites rapides. Mais de moins en moins, maintenant que <a href="https://github.com/sametmax/django-quicky">django_quicky</a> est bien rodé, si je sais que le site va déboucher sur un truc, c&#8217;est plus productif d&#8217;utiliser ce dernier.</p>
<p><a href="http://peewee.readthedocs.org/">peewee</a>, surtout pour introduire les gens à la programmation avec base de données durant les formations. SQLAlchemy c&#8217;est bien trop dur, et l&#8217;ORM Django se ramène avec tout le framework. Mais pour mes besoins rapides, j&#8217;avoue que je tape de plus en plus dans Redis ou du flat file. C&#8217;est souvent du jetable de toute façon et je manipule itertools mieux que SQL ou toute couche ORM au dessus.</p>
<p><a href="http://sametmax.com/grin-le-grep-python-sous-steroid/">grin</a> est toujours là. Parce que je ne me souviens jamais des millions de flags de grep pour obtenir ce que grin donne gratos, comme la coloration, le contexte, la récursivité et l&#8217;exclusion du dossier <em>.git</em>. Parce qu&#8217;il prend les regex Python en compte. Parce qu&#8217;il marche sous n&#8217;importe quelle plateforme supportée par Python de la même manière, y compris Windows, et s&#8217;installe avec un <code>pip install grin --user</code> sans avoir besoin des droits root.</p>
<h2>Ce qui a changé</h2>
<p>Adios dateutil, bonjour <a href="http://sametmax.com/les-time-zones-en-python/">arrow</a>. Ok, je triche un peu, car arrow utilise dateutil sous le capot, mais je n&#8217;en vois jamais la couleur. Arrow est plus simple, plus beau, plus productif, plus mieux. Les dates, telles que ça devrait être dans la lib standard.</p>
<p>Ensuite, au revoir clize, place à <a href="http://sametmax.com/la-plus-belle-maniere-de-parser-les-arguments-de-script-en-python/">docopt</a> pour parser toutes les lignes de commandes. Les fonctionnalités avancées de <a href="http://click.pocoo.org/">click</a> ne m&#8217;ont pas convaincu de migrer, et docopt est tellement intuitif, tellement merveilleux dans son fonctionnement&#8230;</p>
<p><a href="https://github.com/sametmax/minibelt">minibelt</a> fait maintenant partie de tous mes fichiers requirements. Surtout pour son sorted <code>set</code>, son <code>dmerge</code>, ses <code>get</code>, <code>attr</code> et <code>iget</code>. Parfois pour <code>chunk</code> et <code>windows</code>. C&#8217;est tellement rageant de devoir recoder ces petites fonctions pour chaque projet.</p>
<p><a href="http://sametmax.com/remplacer-sed-awk-cut-et-perl-par-python-orgasme-pour-sysadmin/">pyped</a> est de plus en plus utile chaque jour. Depuis l&#8217;article du blog, il a bien évolué et embarque un tas de goodies comme le spliting via options, l&#8217;auto filter ou encore le parsing JSON. Bref, je n&#8217;ai plus touché à <code>sed</code> depuis des mois.</p>
<p><a href="http://sametmax.com/se-simplifier-les-tests-python-avec-pytest/">pytest</a> partout. Je ne touche plus au module unittest de la stdlib ni celui de Django. pytest est la réponse à tout et même plus, c&#8217;est 42 + 1, c&#8217;est la seule raison pour laquelle je fais encore des tests.</p>
<p><a href="https://pypi.python.org/pypi/six/1.7.2">six</a>. Pas parce que j&#8217;aime cette lib, mais parce que je me tape pas mal de conversion Python 2/3 en ce moment, et six est le socle sur lequel repose toutes mes migrations. Pourvue que je n&#8217;ai bientôt plus besoin de l&#8217;utiliser. Oui, oui, je sais, on doit migrer <a href="http://0bin.net/">0bin</a> et tous les autres projets. Un jour.</p>
<p>Pas directement lié à Python, mais pour faire des UI au dessus de mes APIs en Python. jQuery est petit à petit en train d&#8217;être remplacé par <a href="http://angular-ui.github.io/">angularjs</a> que je commence à bien maitriser. Ça mériterait un paquet d&#8217;articles rien que pour le bestiau mais je vais m&#8217;en tenir au 180 drafts qu&#8217;on a déjà en stock :) Et puis jQuery a encore de beaux jours devant lui pour tous les sites qui ont besoin de ref, les sites legacy, les petits sites qui n&#8217;ont pas besoin d&#8217;un bazooka pour l&#8217;UI&#8230;</p>
<p>Un autre truc que j&#8217;utilise tous les jours, c&#8217;est la <a href="http://sametmax.com/cours-et-tutos/">liste des cours</a> du blog avec une recherche type &#8220;site:http://sametmax.com/cours-et-tutos/ mes mots clés&#8221; car le moteur de recherche de wordpress est à chier. Et franchement, je me félicite régulièrement du <a href="https://github.com/sametmax/miroir-du-blog">dump du blog</a> parce qu&#8217;Internet est pas stable ici et la consultation hors ligne devient vite indispensable. Pour cette même raison, j&#8217;ai installé <a href="http://zealdocs.org/">zeal</a> avec la doc de python en local.</p>
<h2>Ce qui est resté au placard</h2>
<p>Je pensais que j&#8217;utiliserais beaucoup <a href="https://github.com/sametmax/templite">templite</a>, mais en fait pas du tout. Comme minibelt contient mes fonctions favorites, <a href="http://sametmax.com/batbelt-la-lib-des-petits-outils-python-qui-vont-bien/">batbelt</a>, sa grande soeur, s’ennuie, surtout qu&#8217;elle n&#8217;est toujours pas compatible Python 3.</p>
<p>Plus de Beautiful soup. Je ne parse plus de HTML, il y a des APIs partout&#8230; Plus de Fabric. J&#8217;utilise docker et je déploie mes instances à la main (j&#8217;ai pas 500 serveurs à gérer).</p>
<p>J&#8217;ai aussi fait un long essai du shell fish, mais je ne suis pas convaincu et je vais retourner à ce bon vieux bash.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=10520&amp;md5=f204afcb23124a9b49cb408dcefa1064" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=10530
title: Encore une raison d’aimer WAMP
uri: Encore-une-raison-d-aimer-WAMP
url: http://sametmax.com/encore-une-raison-daimer-wamp/
content:
<p>RPC et Pub/Sub sont des modes de communications dont on a besoin tous les jours.</p>
<p>La preuve en est que :</p>
<ul>
<li>On utilise massivement HTTP, qui n&#8217;est jamais qu&#8217;un RPC du pauvre.</li>
<li>La plupart des frameworks expose un modèle d’évènements, slots ou de signaux, ce qui n&#8217;est jamais qu&#8217;un Pub/Sub mais uniquement en local.</li>
</ul>
<p>En fait, on les utilise, mais en bricolé, et limité. On s&#8217;en tient à ça parce que ça marche facilement et partout. Jusqu&#8217;ici, l&#8217;alternative, c&#8217;était la solution propre type SOAP, CORBA, etc., qui est ni simple, ni fun à utiliser. Massivement chiant serait plutôt le bon terme, en fait.</p>
<p>Mais ça n&#8217;a pas empêché les gens de tenter de faire leurs propres solutions :</p>
<ul>
<li><a href="https://t.co/aSFkhCYVCG">GO</a></li>
<li><a href="https://github.com/capaj/socket.io-rpc">JS</a></li>
<li><a href="http://pubsub.sourceforge.net/installation.html#system-requirements">Python</a></li>
<li><a href="http://www.rabbitmq.com/tutorials/tutorial-six-ruby.html">Ruby</a></li>
<li><a href="http://support.microsoft.com/kb/833401">Exchange</a></li>
<li><a href="http://docs.closure-library.googlecode.com/git/class_goog_pubsub_PubSub.html">Clojure</a></li>
</ul>
<p>Si vous avez suivi le compte twitter, vous avez du voir que j&#8217;en trouve régulièrement.</p>
<p>Bien entendu, aucun de ces projets n&#8217;implémente à la fois RPC _et_ Pub/Sub. Aucun ne se base sur un standard. Et aucun ne permet à plusieurs langages / stack technos de parler entre eux.</p>
<p><a href="http://sametmax.com/crossbar-le-futur-des-applications-web-python/">WAMP</a> résout tout ça, en permettant RPC et Pub/Sub, en temps réel, à travers le réseau, entre composants hétérogènes, le tout basé sur un standard.</p>
<p>Au passage, l&#8217;API flaskesque a été acceptée par l&#8217;équipe de Tavendo, et on a une branche qui est bien avancée sur le sujet. Après je m&#8217;attaquerai à faire un bon gros tuto sur la question.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=10530&amp;md5=b7d9f04b7ff9e1eeabc21ced44cbdffd" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=10575
title: Redirection 307 et 308
uri: Redirection-307-et-308
url: http://sametmax.com/redirection-307-et-308/
content:
<p>Le standard HTTP 1.1 vient de <a href="http://evertpot.com/http-11-updated/">subir une mise à jour</a>.</p>
<p>Oui, LE standard HTTP 1.1. La fameuse <a href="http://tools.ietf.org/html/rfc2616">RFC2616</a>, qui n&#8217;a pas été touchée depuis l&#8217;année de sortie de The Matrix (coïncidence ? Je ne pense pas&#8230;).</p>
<p>Bref, qu&#8217;est-ce qui change ?</p>
<p>Essentiellement la forme, qui permettra à la RFC de HTTP 2.0 de faire référence à des parties de celle de la HTTP 1.1, maintenant divisée en 8, et évitera de se répéter.</p>
<p>Le web ne va donc pas casser.</p>
<p>Mais il y a quand même intronisation officielle de la redirection 308, qui est à la 301 ce que la 307 est à la 302.</p>
<p>Je me doute que ça vous parle autant qu&#8217;un personnage de film de Charlie Chaplin en fond d&#8217;écran d&#8217;un Windows avec driver realtek.</p>
<p>Pour rappel, quand un serveur HTTP répond à un client, il lui renvoie un code pour indiquer la nature de sa réponse. Quand tout va bien, c&#8217;est 200, quand la page n&#8217;est pas trouvée, c&#8217;est le fameux 404, quand le serveur est en erreur, c&#8217;est une 50x, etc.</p>
<p>Quand le serveur renvoie un code 30x, c&#8217;est généralement une redirection : on dit au client, ce que tu cherches est ailleurs, et le client, recevant ce code, fait donc une seconde requête, sur la nouvelle adresse.</p>
<p>Le code 301 indique une redirection permanente, ce qui signifie que le client peut considérer que c&#8217;est la nouvelle adresse qui remplace l&#8217;ancienne, pour toujours.</p>
<p>Le code 302 indique une redirection temporaire, généralement on utilise ça pour orienter le client sur le site à la suite d&#8217;une action, comme la saisie d&#8217;un formulaire.</p>
<p>Mais ces deux codes ont une particularité : le client effectue une simple requête GET vers la nouvelle adresse. Si vous avez fait une requête complexe avant, par exemple une requête POST avec plein de paramètres, le client va se rediriger avec une nouvelle requête GET basique, toute l&#8217;information précédente est perdue.</p>
<p>Cela peut être ce que l&#8217;on veut. Mais parfois, on souhaite que le client fasse la redirection avec une copie exacte de la requête initiale.</p>
<p>C&#8217;est ce que fait le code 307 : une redirection temporaire, mais avec la même requêtes. C&#8217;est comme la 302, donc, mais répète la même requête deux fois.</p>
<p>Le code 308 demande aussi une redirection en répétant la requête, mais une redirection permanente, comme la 301.</p>
<p><del datetime="2014-06-16T07:31:44+00:00">C&#8217;est ce dernier qui a été ajouté officiellement au protocole, puisqu&#8217;il est déjà supporté par la plupart des navigateurs : même <a href="http://blogs.msdn.com/b/ieinternals/archive/2012/03/29/http-308-permanent-redirect-pushing-the-web-forward-by-breaking-unwanted-forward-compatibility.aspx">IE le comprends depuis 2008</a>.</del> </p>
<p>(le support est vraiment aléatoire, voir comments)</p>
<p>Par curiosité, vous pouvez tester la redirection <a href="http://webdbg.com/test/308/">ici</a>.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=10575&amp;md5=e5a69778e77419a03796548cfa36702d" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=10807
title: Alzheimer
uri: Alzheimer
url: http://sametmax.com/alzheimer/
content:
<p><em>Visiblement j&#8217;ai raté mon coup. Les gens voient l&#8217;article comme anti-microsoft alors que je voulais juste souligner la faciliter à oublier qui sont les ordures en prenant un exemple criant.</em></p>
<p>Si il y a bien un truc qui me fait rager, c&#8217;est la capacité de l&#8217;homme  à oublier à quel point les gens ont été des connards.</p>
<p>Ça marche en politique, en commerce, dans le monde de l&#8217;art, et même dans son entourage proche, avec les relations amicales et amoureuses.</p>
<p>Partout en fait. Si quelqu&#8217;un fait une grosse crasse, il pourra toujours attendre, et revenir plus tard. Pouf, lavé. En fait, <strong>il vaut mieux faire une grosse saloperie de temps en temps, et avoir une bonne image, que d&#8217;être quelqu&#8217;un de bien sans communiquer dessus.</strong> Pour les boites, mais pour vous en tant que personne aussi évidement.</p>
<p>Prenez par exemple cette <a href="http://imgur.com/gallery/DTDsH0P">interview de Bill Gates</a>. </p>
<p>Je prends Bill Gates comme exemple, hein, il y en a beaucoup comme lui.</p>
<p>Lisez les commentaires sous l&#8217;interview, vous allez-voir, c&#8217;est atterrant.</p>
<p>Déjà, dois-je souligner le fait que le gars utilise une technique de rhétorique de comptoir pour se mettre de la pommade et que ça passe sans problème.</p>
<p>Dès le début, je trouve ça irritant que le public soit aussi con.</p>
<p>Quand on se traine les casseroles qu&#8217;il a et qu&#8217;à la question &#8220;c&#8217;est quoi le mythe le plus ennuyeux à votre propos&#8221; il répond &#8220;qu&#8217;on dise que je suis trop bien, lol&#8221;, et que personne ne tique&#8230; Merde !</p>
<p>C&#8217;est dans tous les livres les plus pourris sur les entretiens d&#8217;embauche, la première technique qu&#8217;on enseigne pour répondre à la question &#8220;quel est votre plus gros point faible&#8221;.</p>
<p>Mais passons, ce n&#8217;est pas le sujet de l&#8217;article.</p>
<p>Le sujet, c&#8217;est qu&#8217;au cours des années, Microsoft, sous la direction de Billy, nous a <a href="http://en.wikipedia.org/wiki/Criticism_of_Microsoft">pourri la vie</a> avec :</p>
<ul>
<li>L&#8217;enfermement de ses utilisateurs.</li>
<li>Le troll de copyright.</li>
<li>Des licences abusives.</li>
<li>Le mauvais traitement de ses employés.</li>
<li>Céder à la censure.</li>
<li>Collaboration avec la NSA.</li>
<li>IE6.</li>
</ul>
<p>Chacun de ces points mérite à lui seul de ranger Gates dans la catégorie connard, et ne plus lui accorder de crédit. Tous ces points ensembles&#8230;</p>
<p>Mais non, apparemment ce n&#8217;est pas grave. On peut mépriser ses clients, ses employés, les lois, et avoir l&#8217;aval du public. Les faits, tout le monde s&#8217;en bat les steaks.</p>
<p>En fait, les gens n&#8217;associent pas du tout la compagnie avec l&#8217;homme. Deux entités distinctes. Il vient d&#8217;où son pognon à William, d&#8217;après vous ?</p>
<p>Enfin je dis ça, les gens ont pardonné à Microsoft aussi. Comme ils pardonnent à <a href="http://sebsauvage.net/rhaa/index.php?q=thecriclinks">Apple</a> et comme il pardonneront à <a href="http://doonesbury.washingtonpost.com/strip/archive/2014/06/01">Google</a>.</p>
<p>Pourtant, ce n&#8217;est pas comme si c&#8217;était un petit scandale et puis terminé. Non, ils en remettent une couche régulièrement:</p>
<ul>
<li><a href="http://www.forbes.com/sites/alexandrawrage/2013/03/20/microsoft-whistleblower-allegations-highlight-global-corruption-risks/">Corruption</a></li>
<li><a href="http://www.tomshardware.fr/articles/pots-de-vin-microsoft,1-45570.html">Pot de vin</a></li>
<li><a href="http://www.sebsauvage.net/rhaa/?2005/03/02">Plagiat</a></li>
<li><a href="http://www.networkworld.com/community/blog/blast-past-microsoft-accused-monopolistic-pra">Abus de position dominante</a></li>
<li><a href="http://en.wikipedia.org/wiki/United_States_v._Microsoft_Corp.">Établissement d&#8217;un monopole</a></li>
<li><a href="http://arstechnica.com/information-technology/2013/03/microsoft-accused-of-locking-out-linux-in-eu-antitrust-complaint/">Entrave à la libre concurrence</a></li>
<li><a href="http://lesmoutonsenrages.fr/2012/01/12/le-mariage-gates-et-monsanto-attention-danger-pour-la-planete/">Financement des pires lobbies légaux de la planète</a></li>
<li><a href="http://www.zdnet.com/blog/security/one-year-old-unpatched-windows-token-kidnapping-under-attack/2894">Mépris de la sécurité de ses utilisateurs.</a></li>
<li><a href="http://sebsauvage.net/rhaa/index.php?2009/05/09/15/48/27-microsoft-sabote-odf">Sabotage</a></li>
<li><a href="http://sebsauvage.net/rhaa/index.php?2007/05/23/09/34/59-microsoft-relance-sa-campagne-quot-get-the-facts-quot-">Publicité mensongère</a></li>
<li><a href="http://appft1.uspto.gov/netacgi/nph-Parser?Sect1=PTO1&#038;Sect2=HITOFF&#038;d=PG01&#038;p=1&#038;u=%2Fnetahtml%2FPTO%2Fsrchnum.html&#038;r=1&#038;f=G&#038;l=50&#038;s1=%2220040230959%22.PGNR.&#038;OS=DN/20040230959&#038;RS=DN/20040230959">Brevets abusifs</a></li>
<li ><a href="http://www.microsoft-watch.com/content/vista/ballmers_bold_vista_admission.html?kc=MWRSS02129TX1K0000535">Vente de produits ouvertement pas finis au prix d&#8217;un produit de haute technologie</a></li>
<li><a href="http://www.asymco.com/2011/05/27/microsoft-has-received-five-times-more-income-from-android-than-from-windows-phone/">Business model basé sur l&#8217;extorsion</a></li>
<li><a href="http://www.salon.com/2011/09/06/wikileaks_microsoft_tunisia">Soutien de dictateurs</a></li>
<li><a href="http://sebsauvage.net/rhaa/?2010/01/06/13/21/41-microsoft-peine-de-mort-par-flashage">Destruction de votre matos à distance</a></li>
</ul>
<p>J&#8217;arrête là car la liste n&#8217;en finit pas, des dizaines de scandales (en plus, là je ne prends qu&#8217;un exemple par type de scandale ici, sinon&#8230;), plus ou moins gros, par an. Tellement que c&#8217;en est lassant.</p>
<p>Pourtant, un seul d&#8217;entre eux devrait suffire à les renvoyer dans les cordes. Là, il y a de quoi rempir un manuel d&#8217;exercice de conclusions pénales, et ça ne fait rien.</p>
<p>Je crois que passée une certaine quantité de magouilles, y a un switch qui s&#8217;active dans le cervau qui amorce un <a href="https://en.wikipedia.org/wiki/SEP_field">SEP field</a>.</p>
<p>Ça me fait penser à cette blague, où Bush discute avec Bin Laden, et un conseiller en com leur demande ce qu&#8217;ils foutent :</p>
<blockquote>
<ul>
<li>On fait nos plans. On a décidé de tuer 30 000 américains, 140 000 irakiens et un homosexuel séropositif.</li>
<li>Pourquoi un homo ?</li>
<li> Tu vois Ousama, je te l&#8217;avais dit, tout le monde s&#8217;en branle des autres !</li>
</ul>
</blockquote>
<p>Après il y a des gens qui disent &#8220;<em>oui mais Microsoft est trop gros, il ne peut pas contrôler tout ça</em>&#8220;.</p>
<p>MS a la taille choisie par Bill Gates, il est responsable de ce fait, il l&#8217;a décidé, chaque jour. S&#8217;il était, à l&#8217;époque, assez compétent pour être à la tête de la boite, il est responsable de chacune de ces merdes. S&#8217;il n&#8217;était pas compétent, on avait un abruti aux commandes d&#8217;un tank dans un jardin d&#8217;enfants. Dans tous les cas, c&#8217;est grave.</p>
<p>Il y a aussi le &#8220;<em>oui, mais il a fait beaucoup pour l&#8217;informatique</em>&#8220;. </p>
<p>Déjà, ça reste à démontrer. Qui me dit que si on supprimais M$ à sa naissance, l&#8217;informatique ne se porterait pas mieux ? Improuvable.</p>
<p>Ensuite, <a href="http://www.reuters.com/article/2013/11/04/us-jnj-settlement-idUSBRE9A30MM20131104">Johnson &amp; Johnson</a> ont aussi &#8220;fait beaucoup&#8221; pour la pharmaceutique, mais je ne leur confierais pas <a href="http://www.framablog.org/index.php/post/2014/05/21/microsoft-academie-de-paris">l&#8217;hébergement d&#8217;un colloque du ministère de la santé</a>. (J&#8217;étais parti pour un exemple de rétablissement économique de l&#8217;Allemagne en 40, mais j&#8217;ai reçu un email de Godwin).</p>
<p>Tout ça pour dire que parce que quelqu&#8217;un a (peut-être) fait un peu de bien, ça ne l&#8217;absout pas de toutes les merdes qu&#8217;il a faites. Sinon, je vous mets une baffe dans la gueule, je vous fais un bisou, et on est quitte ?</p>
<p>Ensuite, il y a l&#8217;aspect moral du simple fait qu&#8217;il a concentré, pour sa petite personne, pendant des dizaines d&#8217;années, des milliards de dollars. Il en donne la moitié aujourd&#8217;hui, mais les gens semblent oublier qu&#8217;ils les a retirés de l&#8217;économie et bloqués. Pendant toute sa vie.</p>
<p>Je ne parle pas du flux d&#8217;argent qu&#8217;il a fait circuler de l&#8217;économie à ses comptes, et de ses comptes à l&#8217;économie. Non. Je parle de ce qu&#8217;il a accumulé dessus, c&#8217;est à dire ce qui est resté là, à attendre.</p>
<p>Et oui, c&#8217;est ce que personne ne dit quand on parle des ultra-riches : la monnaie, ce n&#8217;est pas juste un nombre ou du papier, c&#8217;est la représentation d&#8217;une ressource, en grande majorité le travail humain. Quand ce sont quelques millions, l&#8217;impact n&#8217;est pas énorme. Quand ce sont quelques milliards, <strong>ce sont des milliers d&#8217;années de travail de personnes qui restent en suspens, pour le plaisir d&#8217;un seul homme.</strong></p>
<p>Enfin le plaisir : si il a plusieurs milliards en banque, c&#8217;est qu&#8217;il n&#8217;en dépense pas la majorité. C&#8217;est une décoration. Un blason. Et après il a redonné, excusez-moi, la moitié ! On l&#8217;admire pour ça ? Il annonce qu&#8217;à sa mort, une fois qu&#8217;il n&#8217;aura plus besoin de son aura sociale (putain, le pin&#8217;s à $100 milliards les gars), il va tout refiler, et on en parle comme d&#8217;un grand homme.</p>
<p>Donc le gars a créé une boite qui, dans notre système économico-social, lui a permis d&#8217;immobiliser l&#8217;équivalent du PIB d&#8217;un petit pays. Pour rien au final, car cela représente la somme de ce qu&#8217;il n&#8217;a PAS utilisé pendant toutes ces années. Il a gardé ce pognon pour la déco.</p>
<p>Et on l&#8217;applaudit pour ça ?</p>
<p>Quand quelqu&#8217;un est riche, il n&#8217;a pas de responsabilité aux yeux du public. Les gens l&#8217;envient. Ou le respectent. Mais personne ne pense qu&#8217;il a le devoir d&#8217;assumer les conséquences de ce qu&#8217;il fait (ou ne fait pas) avec son argent.</p>
<p>En plus, la grosse blague, c&#8217;est que les organisations philanthropiques aux USA ont le droit de gérer un portefeuille d&#8217;investissement. Ce qui donne <a href="http://www.agoravox.fr/tribune-libre/article/bill-gates-philanthrope-oui-mais-19525">ceci</a> :</p>
<blockquote><p>Comme la plupart des organisations philanthropiques, la Gates Foundation donne chaque année au moins 5% de son capital pour payer un minimum d’impôts. [...] Les 95% restants sont investis. [...] Et là, on en arrive au point soulevé par les journalistes du LA Times qui se sont aperçus que les entreprises dans lesquelles la fondation possédait des parts et dont les objectifs allaient à l’encontre de ses buts caritatifs représentaient 41 % de ses actifs, soit 8,7 milliards de dollars. </p></blockquote>
<p>En gros le gars fait du pognon en finançant des boites qui sont responsables de la destruction contre laquelle luttent les associations qu&#8217;il prétend aider.</p>
<p>Au passage, en donnant son pognon à la fondation, Bilou s&#8217;évite aussi de payer pas mal d&#8217;impôts. Argent qu&#8217;il réinvestit dans cette structure payant elle-même peu d&#8217;impôts qui peut alors investir dans ce qui arrange notre bonhomme. <a href="http://www.framablog.org/index.php/post/2009/03/05/fondation-bill-et-melinda-gates">C&#8217;est pour aider le monde</a>, ma bonne dame.</p>
<p>Donc Bill Gates est une ordure, et il y a des gens pour le défendre, parce que c&#8217;est une ordure socialement acceptable, et très visible. C&#8217;est vrai qu&#8217;en photo il a l&#8217;air super sympa.</p>
<p><strong>Mais ce n&#8217;est pas Bill Gates qui m&#8217;énerve le plus. Ce n&#8217;est qu&#8217;un exemple. Il y en a des milliers comme lui.</p>
<p>Ce qui m&#8217;énerve le plus, c&#8217;est chaque abruti qui oublie.</strong></p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=10807&amp;md5=8d6d192f10b31fbf9c6327fc315d056c" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=10596
title: Comment fonctionne HTTP ?
uri: Comment-fonctionne-HTTP
url: http://sametmax.com/comment-fonctionne-http/
content:
<p>Plus je fais du dev Web, plus je m&#8217;aperçois que beaucoup de mes collègues n&#8217;ont aucune idée de comment fonctionne HTTP sous le capot. Comme vous le savez, ma règle numéro 1 c&#8217;est qu&#8217;<a href="http://sametmax.com/bien-expliquer-quelque-chose-les-regles-de-base/">il n&#8217;y a rien d&#8217;évident</a>, donc petit tuto pour expliquer les bases.</p>
<p>On ne va pas rentrer dans les petits détails, juste une petite intro histoire de savoir ce qui se passe derrière ce script PHP ou cette application bottle.</p>
<p>Article long, vous connaissez la chanson.</p>

<!-- iframe plugin v:2.3 - wordpress.org/extend/plugins/iframe/ -->
<iframe width="420" height="315" src="//www.youtube.com/embed/mDarUeXPFco" frameborder="0" scrolling="no" class="iframe-class"></iframe>
<p>Et puis c&#8217;est dans le ton de l&#8217;actu ^^</p>
<h2>La logique de client / serveur</h2>
<p>(<a href="http://sametmax.com/bien-expliquer-quelque-chose-les-regles-de-base/">Je me repompe moi-même</a>)</p>
<p>Se balader sur le Web, c&#8217;est comme aller au resto. On est un client, on demande quelque chose au serveur, le serveur va voir en cuisine, et revient avec la bouffe, ou une explication sur l&#8217;absence de la bouffe (mais jamais pourquoi la bouffe est dégueulasse, allez comprendre):</p>
<div id="attachment_965" class="wp-caption aligncenter" style="width: 533px"><a href="media/fba86e68.http.png" data-original-source="http://sametmax.com/wp-content/uploads/2012/06/http.png"><img class=" wp-image-965 " title="Le protocole HTTP, en gros" src="media/fba86e68.http.png" data-original-source="http://sametmax.com/wp-content/uploads/2012/06/http.png" alt="Schéma du protocole HTTP, en gros" width="523" height="666" /></a><p class="wp-caption-text">Le protocole HTTP, en (très) gros</p></div>
<p>Ce cycle requête/réponse se déroule des centaines de fois quand on parcours un site Web. Chaque lien cliqué déclenche une requête GET, et la page suivante ne s&#8217;affiche que parce qu&#8217;on a reçu la réponse contenant le HTML de celle-ci. Les formulaires, les requêtes AJAX, la mise à jour de vos Tweets sur votre téléphone, tout ça fonctionne sur le même principe.</p>
<p>Donc, sur votre site Web, Firefox, Chrome et les autres vont faire une requête à une machine, votre machine contient un code (si vous êtes dev, votre code :) qui va recupérer cette requête et générer une réponse.</p>
<h2>Tout est texte</h2>
<p>Généralement, les développeurs utilisent des outils sophistiqués pour écrire des sites Web. Si bien que quand on écrit du code, on ne voit pas vraiment la requête et la réponse, mais des fonctions, des objets, du HTML&#8230; Comment ça arrive et comment ça repart est géré automatiquement.</p>
<p>Regardons ce qui se passe quand ce n&#8217;est PAS géré automatiquement.</p>
<p>Voici le code d&#8217;un petit serveur HTTP écrit en Python 3. Il accepte n&#8217;importe quelle requête sur le port 7777 et retourne toujours une page avec marqué &#8220;Coucou&#8221;.</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> asyncio
&nbsp;
<span style="color: #808080; font-style: italic;"># Le texte de la réponse qu'on va renvoyer</span>
COUCOU = b<span style="color: #483d8b;">&quot;&quot;&quot;HTTP/1.1 200 OK
Date: Fri, 16 Jun 2014 23:59:59 UTC
Content-Type: text/html
&nbsp;
&lt;html&gt;
&lt;body&gt;
&lt;h1&gt;Coucou&lt;/h1&gt;
&lt;/body&gt;
&lt;/html&gt;&quot;&quot;&quot;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># La fonction qui gère chaque requête et qui renvoie une réponse</span>
<span style="color: #808080; font-style: italic;"># pour chacune d'entre elles. La même réponse à chaque fois pour cet</span>
<span style="color: #808080; font-style: italic;"># exemple, mais on peut fabriquer une réponse différente si on veut.</span>
<span style="color: #ff7700;font-weight:bold;">def</span> handle_request<span style="color: black;">&#40;</span>request, response<span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;"># On lit la requête</span>
    data = <span style="color: #ff7700;font-weight:bold;">yield</span> <span style="color: #ff7700;font-weight:bold;">from</span> request.<span style="color: black;">read</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">1000000</span><span style="color: black;">&#41;</span>
    <span style="color: #808080; font-style: italic;"># On affiche son contenu. Surprise, c'est que du texte !</span>
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>data.<span style="color: black;">decode</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'ascii'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
    <span style="color: #808080; font-style: italic;"># On écrit notre réponse, que du texte aussi !</span>
    response.<span style="color: black;">write</span><span style="color: black;">&#40;</span>COUCOU<span style="color: black;">&#41;</span>
    <span style="color: #808080; font-style: italic;"># On ferme la connexion : le protocole HTTP est stateless,</span>
    <span style="color: #808080; font-style: italic;"># c'est à dire qu'il n'y a pas de maintien d'un état</span>
    <span style="color: #808080; font-style: italic;"># côté client ou serveur et chaque requête est indépendante</span>
    <span style="color: #808080; font-style: italic;"># de toutes les autres.</span>
    response.<span style="color: black;">close</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">if</span> __name__ == <span style="color: #483d8b;">'__main__'</span>:
    <span style="color: #808080; font-style: italic;"># Machinerie pour faire tourner le serveur :</span>
    <span style="color: #808080; font-style: italic;"># Récupération de la boucle d'événements.</span>
    loop = asyncio.<span style="color: black;">get_event_loop</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    <span style="color: #808080; font-style: italic;"># Création du serveur qui écoute sur le port 7777</span>
    <span style="color: #808080; font-style: italic;"># et qui va appeler notre fonction quand il reçoit</span>
    <span style="color: #808080; font-style: italic;"># une requête.</span>
    f = asyncio.<span style="color: black;">start_server</span><span style="color: black;">&#40;</span>handle_request, port=<span style="color: #ff4500;">7777</span><span style="color: black;">&#41;</span>
    <span style="color: #808080; font-style: italic;"># Installation du serveur dans la boucle d'événements.</span>
    loop.<span style="color: black;">run_until_complete</span><span style="color: black;">&#40;</span>f<span style="color: black;">&#41;</span>
    <span style="color: #808080; font-style: italic;"># On démarre la boucle d'événement.</span>
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Serving on localhost:7777&quot;</span><span style="color: black;">&#41;</span>
    loop.<span style="color: black;">run_forever</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Si vous êtes dev, vous commencez à comprendre combien</span>
<span style="color: #808080; font-style: italic;"># les libs et frameworks qui gèrent tout ce bordel pour</span>
<span style="color: #808080; font-style: italic;"># vous sont fantastiques.</span></pre></div></div>

<p>Si on lance le serveur et qu&#8217;on visite la page <code>http://localhost:7777</code> sur un navigateur, on va alors voir ceci dans le terminal où tourne le serveur :</p>
<pre>$ python3 server.py
Serving on localhost:7777
GET / HTTP/1.1
Host: 127.0.0.1:7777
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:30.0) Gecko/20100101 Firefox/30.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: fr,fr-fr;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
DNT: 1
Connection: keep-alive
Cache-Control: max-age=0
</pre>
<p>C&#8217;est la requête envoyée par notre client, et reçue par notre serveur. &#8220;Aller&#8221; sur l&#8217;adresse veut dire en fait que votre navigateur envoie ce morceau de texte.</p>
<p>Juste après, mon serveur renvoie aussi du texte. Toujours le même dans notre cas :</p>

<div class="wp_syntax"><div class="code"><pre class="html" style="font-family:monospace;">HTTP/1.1 200 OK
Date: Fri, 16 Jun 2014 23:59:59 UTC
Content-Type: text/html
&nbsp;
&lt;html&gt;
&lt;body&gt;
&lt;h1&gt;Coucou&lt;/h1&gt;
&lt;/body&gt;
&lt;/html&gt;</pre></div></div>

<p>Le navigateur l&#8217;interprète, et vous fabrique cette page :</p>
<div id="attachment_10597" class="wp-caption aligncenter" style="width: 335px"><a href="media/552cfa12.get.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/06/get.png"><img src="media/552cfa12.get.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/06/get.png" alt="" title="Vous contemplez le Web de 1995" width="325" height="186" class="size-full wp-image-10597" /></a><p class="wp-caption-text">Vous contemplez le Web de 1995</p></div>
<p>Comme vous pouvez le voir, ce n&#8217;est que du texte tout simple qui est reçu et envoyé.</p>
<p>Quand quelqu&#8217;un développe un site Web, ce qu&#8217;il fait vraiment, c&#8217;est ça. La plupart du temps il ne le voit pas car ses outils lui facilitent la tâche en analysant le texte et en lui donnant des fonctions et des objets pour le manipuler. Mais derrière, c&#8217;est juste du texte.</p>
<p>Quand quelqu&#8217;un surf le Web, ce qu&#8217;il fait vraiment, c&#8217;est ça. Mais le navigateur se charge de le cacher derrière des jolis contrôles, et affiche un résultat bien plus agréable à regarder.</p>
<h2>Structure des requêtes</h2>
<p>Le texte d&#8217;une requête est divisé en 3 parties :</p>
<ul>
<li>L&#8217;action demandée sur la ressource.</li>
<li>Les headers.</li>
<li>Le corps de la requête</li>
</ul>
<p>Prenons notre précédente requête d&#8217;exemple :</p>
<pre>
GET / HTTP/1.1
Host: 127.0.0.1:7777
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:30.0) Gecko/20100101 Firefox/30.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: fr,fr-fr;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
DNT: 1
Connection: keep-alive
Cache-Control: max-age=0</pre>
<p>L&#8217;action demandée sur la ressource est toujours sur la première ligne :</p>
<p><code>GET / HTTP/1.1</code></p>
<p>Elle se divise en 3 parties :</p>
<ul>
<li>Le verbe d&#8217;action : GET, POST, PUT, OPTION, HEAD, etc. C&#8217;est ce qu&#8217;on veut faire sur les données qu&#8217;on demande. Le plus courant sur le Web, c&#8217;est GET (lire la donnée) et POST (créer la donnée, qu&#8217;on utilise souvent pour les formulaires).</li>
<li>Le chemin de la ressource. Où se trouve la ressource à laquelle on souhaite accéder. Ici c&#8217;est &#8220;/&#8221;, la racine, mais ça peut être &#8220;/user/monique/profile&#8221; par exemple.</li>
<li>La version du protocole utilisé. Aujourd&#8217;hui tout le monde utilise HTTP en version 1.1, donc ça ne change pas vraiment.</li>
</ul>
<p>Notez bien que le chemin de la ressource n&#8217;a pas à correspondre à un chemin réel d&#8217;un fichier sur l&#8217;ordinateur. Une ressource est quelque chose de complètement virtuel, quelque chose que mon programme met à disposition selon mes désirs. Si c&#8217;est un fichier, très bien, mais ce n&#8217;est pas obligatoire, et je peux générer n&#8217;importe quelle réponse qui me plait.</p>
<p>En effet, si je vais sur l&#8217;adresse <code>http://127.0.0.1:7777/user/monique/profile/</code>, vous notez que mon serveur continue de marcher. Il reçoit simplement la requête :</p>
<pre>GET /user/monique/profile/ HTTP/1.1
...
</pre>
<p>C&#8217;est à mon serveur de décider ce qu&#8217;il choisit de faire avec le chemin <code>/user/monique/profile/</code>. Ici il est un peu con et continue de renvoyer &#8220;coucou&#8221;.</p>
<p>Bien, on vient de voir &#8220;L&#8217;action demandée sur la ressource&#8221;, voyons maintenant les headers :</p>
<pre>Host: 127.0.0.1:7777
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:30.0) Gecko/20100101 Firefox/30.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: fr,fr-fr;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
DNT: 1
Connection: keep-alive
Cache-Control: max-age=0</pre>
<p>Les headers sont des informations supplémentaires que le client fourni à mon serveur sous la forme :</p>
<pre>Nom-De-L-Information: contenu</pre>
<p><strong>Les sauts de ligne sont très importants.</strong> La première ligne de la requête est &#8220;L&#8217;action demandée sur la ressource&#8221;, puis on met un saut de ligne, ensuite vient un header, puis un saut de ligne, puis un header&#8230; Chaque header doit tenir sur une ligne.</p>
<p>En HTTP/1.1, seul le header <code>Host</code> est obligatoire, mais comme aucun header n&#8217;était obligatoire en HTTP/1.0, beaucoup de serveurs acceptent l&#8217;absence de tout header.</p>
<p>Les headers contiennent généralement des informations sur le client (ex: <code>Accept-Language</code> vous dit quelles langues le client accepte), le contenu de la requête (ex: <code>Content-Length</code> indique la taille de la requête) ou demande un comportement du server (<code>Cache-Control</code> précise comment gérer les ressources qu&#8217;on peut mettre en cache).</p>
<p>Pour &#8220;Le corps de la requête&#8221;, il nous faut ajouter du contenu à notre requête.</p>
<p>Pour cela, faisons une page avec un petit formulaire HTML :</p>

<div class="wp_syntax"><div class="code"><pre class="html" style="font-family:monospace;">&lt;html&gt;
&lt;head&gt;
    &lt;title&gt;Test post&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;form method=&quot;post&quot; action=&quot;http://127.0.0.1:7777/&quot;&gt;
&lt;p&gt;&lt;input type=&quot;test&quot; value=&quot;coucou, tu veux voir mon POST ?&quot; name=&quot;salut&quot;&gt;
&lt;input type=&quot;submit&quot;&gt;&lt;/p&gt;
&lt;/form&gt;
&lt;/body&gt;
&lt;/html&gt;</pre></div></div>

<p>Ce qui nous donne cette page :</p>
<div id="attachment_10598" class="wp-caption aligncenter" style="width: 335px"><a href="media/7dfeb501.post.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/06/post.png"><img src="media/7dfeb501.post.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/06/post.png" alt="Capture d&#039;écran d&#039;un simple formulaire web sous firefox" title="Techniquement, on peut poster un formulaire avec une requête GET, mais shut..." width="325" height="186" class="size-full wp-image-10598" /></a><p class="wp-caption-text">Techniquement, on peut poster un formulaire avec une requête GET, mais shut...</p></div>
<p>Si on active le formulaire, notre serveur affiche cette requête :</p>
<pre>POST / HTTP/1.1
Host: 127.0.0.1:7777
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:30.0) Gecko/20100101 Firefox/30.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: fr,fr-fr;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
DNT: 1
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 41

salut=coucou%2C+tu+veux+voir+mon+POST+%3F</pre>
<p>Déjà, vous notez que le verbe d&#8217;action a changé : <code>POST / HTTP/1.1</code>.</p>
<p>Ensuite, à la fin de la requête, on laisse une ligne vide, puis on a de nouveau du texte : </p>
<pre>salut=coucou%2C+tu+veux+voir+mon+POST+%3F</pre>
<p>C&#8217;est le corps de la requête.</p>
<p>C&#8217;est comme ça que le serveur reçoit le contenu des données des formulaires, et c&#8217;est ce qu&#8217;on retrouve dans la variable <code>$_POST</code> en PHP ou <code>request.POST</code> en Django</p>
<p>Encore une fois, les outils de programmation évitent au codeur de travailler avec du charabia, et le transforme en quelque chose de facile à comprendre et à manipuler.</p>
<h2>Structure des réponses</h2>
<p>C&#8217;est pareil, ma bonne dame. Reprenons notre exemple de réponse :</p>

<div class="wp_syntax"><div class="code"><pre class="html" style="font-family:monospace;">HTTP/1.1 200 OK
Date: Fri, 16 Jun 2014 23:59:59 UTC
Content-Type: text/html
&nbsp;
&lt;html&gt;
&lt;body&gt;
&lt;h1&gt;Coucou&lt;/h1&gt;
&lt;/body&gt;
&lt;/html&gt;</pre></div></div>

<p>Première ligne, on précise le protocole, puis le <a href="http://fr.wikipedia.org/wiki/Liste_des_codes_HTTP">code de réponse</a>, qui stipule la nature de votre réponse (tout va bien, une erreur, une redirection, la page n&#8217;existe pas, etc).</p>
<p>Ensuite les headers, puis on saute une ligne, et on met le corps de la réponse. Ici, le code HTML qui va donner notre jolie page &#8220;Coucou&#8221;.</p>
<h2>Tout tient là dedans</h2>
<p>Tout le reste, toutes les fonctionnalités fantastiques du Web (les liens hypertextes, les fichiers statiques JS et CSS inclus, les cookies, les redirections, le cache, la compression&#8230;) ont pour point d&#8217;entrée un de ces 3 éléments de la requête ou de la réponse. C&#8217;est que c&#8217;est un protocole bien foutu. </p>
<p>Enfin, disons, <a href="http://sametmax.com/le-web-nest-plus-http/">presque tout</a> ? :)</p>
<hr />
<p><a href="https://github.com/sametmax/codes-des-articles/tree/master/2014/juin">Télécharger le code de l&#8217;article</a></p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=10596&amp;md5=cb865fe145abb491eb081cf7de0d006b" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=10535
title: Où il est présenté une méthode en Python pour afficher de la vidéo 3-bit dans son terminal.
uri: Où-il-est-présenté-une-méthode-en-Python-pour-afficher-de-la-vidé
url:
http://sametmax.com/ou-il-est-presente-une-methode-en-python-pour-afficher-de-la-video-3-bit-dans-son-terminal/

content:
<p style="text-align: center;"><em><small>Ceci est un post invité de <a href="http://sametmax.com/author/01ivier/">01ivier</a> posté sous licence <a href="http://creativecommons.org/licenses/by/3.0/">creative common 3.0 unported</a>.</small></em></p>
<p>Il est des choses inutiles plus passionnantes que d&#8217;autres.<br />
Il semblerait que j&#8217;ai un petit faible pour les choses inutiles que je fais moi-même.</p>
<p>Car, afficher le contenu de sa webcam dans une console, ça ne sert clairement pas à grand chose mais j&#8217;ai pourtant crié très fort en serrant les poings quand j&#8217;y suis arrivé.</p>
<h2>Capturer de la vidéo en Python.</h2>
<p>Sous Nunux, il existe un joli petit paquet tout beau tout chaud qui permet de gérer du flux vidéo en Python : <strong>python-opencv</strong>.</p>
<p>Alors, zou :</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #c20cb9; font-weight: bold;">apt-get</span> <span style="color: #c20cb9; font-weight: bold;">install</span> python-opencv</pre></div></div>

<p>Et pour afficher sa webcam, seules quelques lignes suffisent :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;">#-*- coding: utf-8 -*-</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">import</span> cv2
&nbsp;
<span style="color: #808080; font-style: italic;"># Choix du périphérique de capture. 0 pour /dev/video0.</span>
cap = cv2.<span style="color: black;">VideoCapture</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">while</span> <span style="color: #008000;">True</span>:
&nbsp;
    <span style="color: #808080; font-style: italic;"># On capture l'image.</span>
    ret,im = cap.<span style="color: black;">read</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># On l'affiche.</span>
    cv2.<span style="color: black;">imshow</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Ma Webcam à moi'</span>,im<span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Et on attend 40 millisecondes pour avoir du 25 images par seconde.</span>
    key = cv2.<span style="color: black;">waitKey</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">40</span><span style="color: black;">&#41;</span></pre></div></div>

<p>GO !!</p>
<p><a href="http://sametmax.com/ou-il-est-presente-une-methode-en-python-pour-afficher-de-la-video-3-bit-dans-son-terminal/mawebcam-2/" rel="attachment wp-att-10677"><img src="media/df3b550b.MaWebCam.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2014/06/MaWebCam.jpg" alt="" title="MaWebCam" width="600" height="337" class="aligncenter size-full wp-image-10677" /></a></p>
<p>Je vais bien me garder de vous faire un tuto sur OpenCV tant cette librairie est puissante (comprendre : j&#8217;y panne que dalle). Si vous êtes curieux, vous pouvez aller faire un tour <a target="_blank" href="http://docs.opencv.org/trunk/doc/py_tutorials/py_tutorials.html">ici</a>.</p>
<p>Et, parce que j&#8217;avais bien d&#8217;autres choses plus intéressantes à faire que d&#8217;aller visiter le lien ci-dessus, j&#8217;ai fait un petit <em>print</em> du <em>im</em> précédent et découvert une liste toute mignonne dont voici la structure:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># Avec des valeurs pour les niveaux comprises entre 0 et 255.</span>
im<span style="color: black;">&#91;</span>n° de ligne<span style="color: black;">&#93;</span><span style="color: black;">&#91;</span>n° de colonne<span style="color: black;">&#93;</span><span style="color: black;">&#91;</span>niveau de bleu, niveau de vert, niveau de rouge<span style="color: black;">&#93;</span></pre></div></div>

<p>J&#8217;étais content car j&#8217;allais pouvoir récupérer les valeurs de chaque pixel de cette façon:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">for</span> ligne <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span>hauteur<span style="color: black;">&#41;</span>:
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">for</span> colonne <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span>largeur<span style="color: black;">&#41;</span>:
&nbsp;
        niv_bleu = im<span style="color: black;">&#91;</span>ligne<span style="color: black;">&#93;</span><span style="color: black;">&#91;</span>colonne<span style="color: black;">&#93;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span>
        niv_vert = im<span style="color: black;">&#91;</span>ligne<span style="color: black;">&#93;</span><span style="color: black;">&#91;</span>colonne<span style="color: black;">&#93;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span>
        niv_rouge = im<span style="color: black;">&#91;</span>ligne<span style="color: black;">&#93;</span><span style="color: black;">&#91;</span>colonne<span style="color: black;">&#93;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">2</span><span style="color: black;">&#93;</span></pre></div></div>

<p>Si, pour un autre projet formidable, je n&#8217;avais pas eu à travailler avec une RasberryPi et ses petites cuisses de bébé, je pense que j&#8217;utiliserai encore cette méthode de bourrin.</p>
<p>Mais voilà, c&#8217;est juste ridicule quand on sait que la liste en question est en fait un array <a target="_blank" href="http://sametmax.com/les-bases-de-numpy/">numpy</a> et qu&#8217;il est 10, 100 fois plus rapide de faire:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">for</span> ligne <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span>hauteur<span style="color: black;">&#41;</span>:
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">for</span> colonne <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span>largeur<span style="color: black;">&#41;</span>:
&nbsp;
        niv_bleu = im.<span style="color: black;">item</span><span style="color: black;">&#40;</span>ligne, colonne, <span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>
        niv_vert = im.<span style="color: black;">item</span><span style="color: black;">&#40;</span>ligne, colonne, <span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>
        niv_rouge = im.<span style="color: black;">item</span><span style="color: black;">&#40;</span>ligne, colonne, <span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Je n&#8217;en suis pas à me dire que la prochaine fois que j&#8217;achèterai un grille-pain, je lirai la notice avant de l&#8217;utiliser, mais presque&#8230;</p>
<p>Petite remarque en passant : les valeurs de rouge, de vert et de bleu étant comprise entre 0 et 255, cela nous donne 256 valeurs pour chaque couleur.<br />
Soit 256 x 256 x 256. Soit 2⁸ x 2⁸ x 2⁸. Soit 2²⁴ ==> les couleurs de notre flux sont codées par défaut sur 24 bits.</p>
<p>À noter qu&#8217;il est tout à fait possible d&#8217;analyser une image sans avoir à l&#8217;afficher, ce qui permet d&#8217;utiliser OpenCV dans un environnement sans gestionnaire de fenêtre.</p>
<h2>Afficher de la couleur dans la console.</h2>
<p>Bon. J&#8217;avais mes niveaux RVB pour chaque pixel. Il me fallait désormais afficher de la couleur dans la console.</p>
<p>Quelques requêtes Duck Duck Go plus tard, je découvre <a target="_blank" href="https://pypi.python.org/pypi/termcolor">termcolor</a> qui fait très bien le job mais dont on peut se passer en regardant <a target="_blank" href="http://www.developpez.net/forums/d448416/autres-langages/python-zope/general-python/mode-console-couleur-shell/#post2706250">les codes ANSI</a> de plus près.</p>
<p>Bien entendu, la grande majorité des consoles étant limitées à 8 couleurs, soit 2³, soit 3-bit je me suis restreint à cette qualité.</p>
<p>Démonstration :</p>
<p><a href="http://sametmax.com/ou-il-est-presente-une-methode-en-python-pour-afficher-de-la-video-3-bit-dans-son-terminal/color-python-console/" rel="attachment wp-att-10569"><img src="media/6fd02b9f.color-python-console.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/06/color-python-console.png" alt="" title="" width="436" height="301" class="aligncenter size-full wp-image-10569" /></a></p>
<p>Il est possible d&#8217;obtenir beaucoup plus de couleurs en combinant les fonds, les caractères et les intensités comme le fait la <a target="_blank" href="http://caca.zoy.org/wiki/libcaca">libcaca</a>, mais on ne joue pas vraiment dans la même cour.</p>
<p>Perso, quand ça s&#8217;est affiché en rouge pour la première fois, j&#8217;ai eu des frissons partout. Parce qu&#8217;il faut bien comprendre que je n&#8217;ai toujours aucune idée de ce que &#8220;\033[&#8221; et autres &#8220;m&#8221; veulent dire. J&#8217;ai copié/collé, c&#8217;est tout. Et dans ces cas là, quand ça marche, c&#8217;est toujours la fête.</p>
<p>Ce qui pourrait être un problème, on le voit à l&#8217;image, c&#8217;est qu&#8217;une fois que j&#8217;ai écrit TATA YOYO en rouge, le prompt devient lui aussi rouge, et ainsi de suite à chaque changement de couleur. Pour remédier à ça, il faut ajouter <strong>\033[0m</strong> à la fin du texte à afficher pour que le reste soit écrit avec la couleur par défaut du terminal.</p>
<p>Démonstration :</p>
<p><a href="http://sametmax.com/ou-il-est-presente-une-methode-en-python-pour-afficher-de-la-video-3-bit-dans-son-terminal/color-python-console-2/" rel="attachment wp-att-10570"><img src="media/e409c858.color-python-console-2.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/06/color-python-console-2.png" alt="" title="color-python-console-2" width="436" height="301" class="aligncenter size-full wp-image-10570" /></a></p>
<p>C&#8217;est d&#8217;ailleurs ce que fait <em>termcolor</em>, sauf que, dans notre cas, nous n&#8217;avons pas besoin de revenir à cette valeur par défaut à chaque affichage de pixel vu que le suivant sera lui aussi coloré.</p>
<p>Je vous en parle seulement parce que vous avez l&#8217;air sympa.</p>
<p>J&#8217;ajouterai qu&#8217;après avoir effectué un benchmark de folie exploitant brillamment les deux points qui clignotent à chaque seconde sur mon radio-réveil, il s&#8217;est avéré que la solution &#8220;maison&#8221; était plus performante que <em>termcolor</em> : mon choix était fait.</p>
<h2>Du pixel au █</h2>
<p>J&#8217;ai renoué contact avec le █ il n&#8217;y a pas si longtemps. Aussi étonnant que cela puisse paraître, alors que je baigne quasi quotidiennement dans l&#8217;informatique depuis 30 ans, il n&#8217;est pas impossible que notre dernière rencontre remonte à 1986 sur le Commodore 64 familial.</p>
<p>Pour vous donner une idée de l&#8217;émotion qui m&#8217;a traversé quand j&#8217;ai revu le █, vous pourriez très clairement user de l&#8217;expression &#8220;le █ d&#8217;Olivier&#8221; en lieu et place de &#8220;la madeleine de Proust&#8221; dans vos discussions. Mais, à l&#8217;oral, le █ passe mal, et c&#8217;est bien dommage.</p>
<p>Pour info, le pseudo unicode de █ c&#8217;est \u2588. </p>
<p>Et, pour afficher un █ en couleur, il suffit de faire comme vu au dessus.</p>
<p><a href="http://sametmax.com/ou-il-est-presente-une-methode-en-python-pour-afficher-de-la-video-3-bit-dans-son-terminal/python-color-console-3-1/" rel="attachment wp-att-10695"><img src="media/6acc808a.python-color-console-3-1.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/06/python-color-console-3-1.png" alt="" title="python-color-console-3-1" width="436" height="301" class="aligncenter size-full wp-image-10695" /></a></p>
<p>Reste à trouver un moyen de passer des millions de couleurs potentielles de notre vidéo aux huit de notre console.</p>
<p>C&#8217;est là que vous allez comprendre pourquoi je me suis acharné avec mes captures d&#8217;écrans. C&#8217;était pour bien vous faire intégrer l&#8217;association entre les couleurs et la valeur qui les code. À savoir :</p>
<p><span style="color:#990000">1 : rouge</span><br />
<span style="color:#009900">2 : vert</span><br />
<span style="color:#999900">3 : jaune</span><br />
<span style="color:#000099">4 : bleu</span><br />
<span style="color:#990099">5 : violet</span><br />
<span style="color:#009999">6 : turquoise</span><br />
<span style="color:#999999">7 : blanc</span></p>
<p>Et là qu&#8217;est qu&#8217;on remarque ?<br />
Que cela respecte la synthèse additive si on attribue 1 au rouge, 2 au vert et 4 au bleu, bien entendu !</p>
<p>1 + 2 = 3 et en synthèse additive rouge + vert = jaune<br />
1 + 4 = 5 et en synthèse additive rouge + bleu = violet<br />
2 + 4 = 6 et en synthèse additive vert + bleu = turquoise<br />
1 + 2 + 4 = 7 et en synthèse additive rouge + vert + bleu = blanc</p>
<p>Mettez-vous à ma place: je venais de découvrir l&#8217;Amérique !</p>
<p>Bon, rétrospectivement, cela ne constitue vraiment rien d’extraordinaire en soi dans la mesure où c&#8217;est ce qui découle logiquement d&#8217;un codage sur 3 bits mis en place par un être humain qui a juste envie de faire simple plutôt que de faire compliqué.</p>
<p>Mais tout de même, sur le moment&#8230;<br />
&#8230; L&#8217;AMÉRIQUE BORDEL ! L&#8217;AMÉRIQUE !</p>
<p>Il devenait alors facile d&#8217;évaluer le degré de présence de chaque composante RVB d&#8217;un pixel puis de déterminer laquelle des 8 couleurs lui correspondait le plus.</p>
<p>Voilà comment je m&#8217;y suis pris :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># On initialise à 0 l'indice du pixel analysé </span>
indice_couleur = <span style="color: #ff4500;">0</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># On analyse le niveau de Bleu du pixel.</span>
<span style="color: #808080; font-style: italic;"># S'il est au dessus du seuil...</span>
<span style="color: #ff7700;font-weight:bold;">if</span> img.<span style="color: black;">item</span><span style="color: black;">&#40;</span>ligne, colonne, <span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span> <span style="color: #66cc66;">&gt;</span> seuil :
&nbsp;
    <span style="color: #808080; font-style: italic;">#...on ajoute 4 à l'indice.</span>
    indice_couleur += <span style="color: #ff4500;">4</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># On analyse le niveau de Vert du pixel.</span>
<span style="color: #808080; font-style: italic;"># S'il est au dessus du seuil...</span>
<span style="color: #ff7700;font-weight:bold;">if</span> img.<span style="color: black;">item</span><span style="color: black;">&#40;</span>ligne, colonne, <span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span> <span style="color: #66cc66;">&gt;</span> seuil :
&nbsp;
    <span style="color: #808080; font-style: italic;">#...on ajoute 2 à l'indice.</span>
    indice_couleur += <span style="color: #ff4500;">2</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># On analyse le niveau de Rouge du pixel.</span>
<span style="color: #808080; font-style: italic;"># S'il est au dessus du seuil...</span>
<span style="color: #ff7700;font-weight:bold;">if</span> img.<span style="color: black;">item</span><span style="color: black;">&#40;</span>ligne, colonne, <span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span> <span style="color: #66cc66;">&gt;</span> seuil :
&nbsp;
    <span style="color: #808080; font-style: italic;"># ...on ajoute 1 à l'indice.</span>
    indice_couleur += <span style="color: #ff4500;">1</span></pre></div></div>

<p>L&#8217;indice obtenu correspond alors au code couleur ANSI à utiliser !!</p>
<p>Je veux dire.</p>
<p>Tout de même.</p>
<p>C&#8217;est super, non ?</p>
<p>&#8230;</p>
<p>Hum&#8230;</p>
<p>&#8230;</p>
<p>Bien, bien&#8230;<br />
C&#8217;est bientôt fini, il me reste juste&#8230;</p>
<h2>Quelques remarques supplémentaires.</h2>
<p><strong>1)</strong> Le noir ANSI est en fait du gris, et c&#8217;est bien moche, j&#8217;ai donc préféré partir du principe que <strong>la console aurait un fond noir</strong> et afficher un &#8220;espace&#8221; pour chaque pixel noir.</p>
<p><strong>2)</strong> print(&#8220;\033[H\033[2J&#8221;) permet d&#8217;effacer la console comme le fait os.system(&#8216;clear&#8217;).<br />
Mais, j&#8217;imagine que ça devait faire trop de <em>033</em> dans le script pour moi, parce que, psychologiquement, ça ne passait pas.<br />
J&#8217;ai un peu discuté avec moi-même et on a fini par décider d&#8217;utiliser le <em>clear</em>.</p>
<p><strong>3)</strong> J&#8217;ai commencé par utiliser la concaténation pour ajouter mes █ colorés à mon <em>texte_image</em> final :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">texte_image += u<span style="color: #483d8b;">&quot;<span style="color: #000099; font-weight: bold;">\0</span>33[3{0}m█&quot;</span>.<span style="color: black;">format</span><span style="color: black;">&#40;</span>indice_couleur<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Mais, Stack Overflow a tapé à la fenêtre et il m&#8217;a dit qu&#8217;il était beaucoup plus rapide de créer une liste puis d&#8217;en joindre les éléments.<br />
J&#8217;ai benchmarké avec mon radio-réveil.<br />
Stack Overflow avait raison.</p>
<p><strong>4)</strong> Par contre, ce que Stack Overflow s&#8217;était bien gardé de me dire, c&#8217;est que l&#8217;affichage en console avait ses propres limites internes.<br />
Bilan, après avoir optimisé mon code du mieux que je le pouvais, j&#8217;ai constaté que le script calculait de toutes façon les <em>texte_image</em> plus vite que la console ne pouvait les afficher.</p>
<p>Ce qui relève un peu du FAIL quand on y pense.</p>
<p>Donc, si vous avez une idée pour que ça ne scintille plus au delà de 25 lignes de hauteur, je suis preneur, sachant que je suis tout à fait à même d&#8217;entendre que j&#8217;ai fait n&#8217;importe quoi dès le début.</p>
<p><em>ÉDIT: Dans les commentaires, Tmonjalo a proposé une solution qui résout le problème du scintillement en faisant revenir le curseur en haut à gauche plutôt que d&#8217;effacer la console. J&#8217;ai donc édité le code en conséquence. Merci à lui.</em></p>
<h2>La totale.</h2>
<p>Voici le script final. Il est diffusé sous les termes de la très sérieuse <a target="_blank" href="http://fr.wikipedia.org/wiki/WTFPL">WTFPL</a>.</p>
<p>Les variables à modifier pour faire des tests sont le <em>seuil</em>, la <em>largeurOut</em> et la <em>hauteurOut</em>.</p>
<p>À noter aussi que si vous faite un petit&#8230;</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">cap = cv2.<span style="color: black;">VideoCapture</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;VotreFilm.avi&quot;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>&#8230; au lieu d&#8217;ouvrir la webcam en <em>/dev/video0</em>, et bien vous allez voir <em>VotreFilm.avi</em> dans la console. Super génial !</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;">#-*- coding: utf-8 -*-</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">import</span> cv2
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">os</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Définition du flux capturé.</span>
<span style="color: #808080; font-style: italic;"># Comme elle sera, de toutes façons, retaillée à la baisse,</span>
<span style="color: #808080; font-style: italic;"># elle est fixée à la valeur la plus petite supportée par la webcam.</span>
<span style="color: #808080; font-style: italic;"># À noter que cette valeur minimale peut varier en fonction de votre cam.</span>
largeurIn = <span style="color: #ff4500;">160</span>
hauteurIn = <span style="color: #ff4500;">120</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Définition du flux qui s'affichera en console.</span>
<span style="color: #808080; font-style: italic;"># À savoir le nombre de caractères en largeur et en hauteur.</span>
largeurOut = <span style="color: #ff4500;">60</span>
hauteurOut = <span style="color: #ff4500;">20</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Seuil de présence des couleurs rouge, vert, bleu dans un pixel. </span>
<span style="color: #808080; font-style: italic;"># Entre 0 et 255.</span>
seuil = <span style="color: #ff4500;">120</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Choix du périphérique de capture.</span>
<span style="color: #808080; font-style: italic;"># Ici /dev/video0</span>
cap = cv2.<span style="color: black;">VideoCapture</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Configuration de la définition du flux.</span>
cap.<span style="color: #008000;">set</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">3</span>, largeurIn<span style="color: black;">&#41;</span>
cap.<span style="color: #008000;">set</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">4</span>, hauteurIn<span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># On efface la console.</span>
<span style="color: #dc143c;">os</span>.<span style="color: black;">system</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'clear'</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># On définit une position de référence pour le curseur.</span>
<span style="color: #808080; font-style: italic;"># En haut à gauche, donc, puisqu'on vient juste d'effacer la console.</span>
<span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: black;">&#40;</span><span style="color: #483d8b;">'<span style="color: #000099; font-weight: bold;">\0</span>33[s'</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Pendant... tout le temps...</span>
<span style="color: #ff7700;font-weight:bold;">while</span> <span style="color: #008000;">True</span>:
&nbsp;
    <span style="color: #808080; font-style: italic;"># On capture une image.</span>
    ret, img = cap.<span style="color: black;">read</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># On retaille l'image capturée.</span>
    img = cv2.<span style="color: black;">resize</span><span style="color: black;">&#40;</span>img,<span style="color: black;">&#40;</span>largeurOut, hauteurOut<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># On initialise une liste qui contiendra tous les éléments de l'image</span>
    liste_image = <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Pour chaque ligne de l'image.</span>
    <span style="color: #ff7700;font-weight:bold;">for</span> ligne <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span>hauteurOut<span style="color: black;">&#41;</span>:
&nbsp;
        <span style="color: #808080; font-style: italic;"># Pour chaque colonne de chaque ligne.</span>
        <span style="color: #ff7700;font-weight:bold;">for</span> colonne <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span>largeurOut<span style="color: black;">&#41;</span>:
&nbsp;
            <span style="color: #808080; font-style: italic;"># On initialise à 0 l'indice du pixel analysé </span>
            indice_couleur = <span style="color: #ff4500;">0</span>
&nbsp;
            <span style="color: #808080; font-style: italic;"># On analyse le niveau de bleu du pixel.</span>
            <span style="color: #808080; font-style: italic;"># S'il est au dessus du seuil...</span>
            <span style="color: #ff7700;font-weight:bold;">if</span> img.<span style="color: black;">item</span><span style="color: black;">&#40;</span>ligne, colonne, <span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span> <span style="color: #66cc66;">&gt;</span> seuil :
&nbsp;
                <span style="color: #808080; font-style: italic;">#...on ajoute 4 à l'indice.</span>
                indice_couleur += <span style="color: #ff4500;">4</span>
&nbsp;
            <span style="color: #808080; font-style: italic;"># On analyse le niveau de bleu du pixel.</span>
            <span style="color: #808080; font-style: italic;"># S'il est au dessus du seuil...</span>
            <span style="color: #ff7700;font-weight:bold;">if</span> img.<span style="color: black;">item</span><span style="color: black;">&#40;</span>ligne, colonne, <span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span> <span style="color: #66cc66;">&gt;</span> seuil :
&nbsp;
                <span style="color: #808080; font-style: italic;">#...on ajoute 2 à l'indice.</span>
                indice_couleur += <span style="color: #ff4500;">2</span>
&nbsp;
            <span style="color: #808080; font-style: italic;"># On analyse le niveau de bleu du pixel.</span>
            <span style="color: #808080; font-style: italic;"># S'il est au dessus du seuil...</span>
            <span style="color: #ff7700;font-weight:bold;">if</span> img.<span style="color: black;">item</span><span style="color: black;">&#40;</span>ligne, colonne, <span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span> <span style="color: #66cc66;">&gt;</span> seuil :
&nbsp;
                <span style="color: #808080; font-style: italic;"># ...on ajoute 1 à l'indice.</span>
                indice_couleur += <span style="color: #ff4500;">1</span>
&nbsp;
            <span style="color: #808080; font-style: italic;"># Si l'indice obtenu est différent de 0...</span>
            <span style="color: #ff7700;font-weight:bold;">if</span> indice_couleur:
&nbsp;
                <span style="color: #808080; font-style: italic;"># ...on ajoute un █ coloré à la liste.</span>
                liste_image.<span style="color: black;">append</span><span style="color: black;">&#40;</span>u<span style="color: #483d8b;">&quot;<span style="color: #000099; font-weight: bold;">\0</span>33[3{0}m█&quot;</span>.<span style="color: black;">format</span><span style="color: black;">&#40;</span>indice_couleur<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
            <span style="color: #808080; font-style: italic;"># Si l'indice est égal à 0...</span>
            <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> indice_couleur:
&nbsp;
                <span style="color: #808080; font-style: italic;"># ...on ajoute un espace (noir ?) à la liste.</span>
                liste_image.<span style="color: black;">append</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot; &quot;</span><span style="color: black;">&#41;</span>
&nbsp;
        <span style="color: #808080; font-style: italic;"># On fait en sorte que le terminal retrouve sa couleur initiale</span>
        liste_image.<span style="color: black;">append</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;<span style="color: #000099; font-weight: bold;">\n</span><span style="color: #000099; font-weight: bold;">\0</span>33[00m&quot;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># On produit un string en mettant bout à bout tous les éléments de la liste</span>
    texte_image = <span style="color: #483d8b;">''</span>.<span style="color: black;">join</span><span style="color: black;">&#40;</span>liste_image<span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># On affiche l'image.</span>
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>texte_image<span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># On replace le curseur à la position de référence.</span>
    <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: black;">&#40;</span><span style="color: #483d8b;">'<span style="color: #000099; font-weight: bold;">\0</span>33[u'</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># On attend 40 millisecondes pour obtenir du 25 images par seconde.</span>
    key = cv2.<span style="color: black;">waitKey</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">40</span><span style="color: black;">&#41;</span></pre></div></div>

<h2> Des vidéos ! Des vidéos !</h2>
<p>Voici une petite vidéo réalisée pour promouvoir un événement à nous. À partir de la 44ème seconde, on peut m&#8217;y voir coiffé d&#8217;un masque de soudeur en train de faire tenir au plafond un donut géant au moyen d&#8217;une batte de base-ball en aluminium :</p>
<p><iframe src="//player.vimeo.com/video/98458658" width="500" height="414" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe></p>
<p>Pour plus d&#8217;information sur cet événement vous pouvez allez voir <a target="_blank" href="http://labomedia.org/du-21-au-26-juillet-2014-open-atelier-version-longue-n4/">ici</a> et admirer, par la même occasion, notre magnifique affiche réalisée en pur Python.</p>
<p>Enfin, compte tenu des tauliers du site, je ne pouvais passer à côté de la figure imposée.<br />
Je vous propose donc un extrait de Deep 3-bit, hommage appuyé à <a target="_blank" href="http://www.ljudmila.org/~vuk/">Vuk Cosic</a> et son légendaire <a target="_blank" href="http://www.youtube.com/watch?v=DGktK6OxfJI">Deep ASCII</a>.</p>
<p><iframe src="//player.vimeo.com/video/98451297" width="500" height="418" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe></p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=10535&amp;md5=475e855a6e9fa095b06e8ec82241c132" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=11013
title: Mais qui donc hérite de ma classe ?
uri: Mais-qui-donc-hérite-de-ma-classe
url: http://sametmax.com/mais-qui-donc-herite-de-ma-classe/
content:
<p>Pas une question que l&#8217;on se pose souvent, à moins d&#8217;avoir une lib qui expose une classe avec beaucoup d&#8217;introspection.</p>
<p>Ceci dit pour la culture G, je me suis dit que ça pourrait intéresser quelques geeks de savoir comment lister les enfants d&#8217;une classe, récursivement.</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> subclasses<span style="color: black;">&#40;</span>cls, _found=<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot; Retourne toutes les classes héritant d'une classe &quot;&quot;&quot;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># On check que la classe est hérite bien de &quot;object&quot;.</span>
    <span style="color: #808080; font-style: italic;"># Utile uniquement pour un code 2.x qui utiliserait</span>
    <span style="color: #808080; font-style: italic;"># des old style classes, qui n'ont pas &quot;__subclasses__&quot;.</span>
    <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #008000;">isinstance</span><span style="color: black;">&#40;</span>cls, <span style="color: #008000;">type</span><span style="color: black;">&#41;</span>:
      <span style="color: #ff7700;font-weight:bold;">raise</span> <span style="color: #008000;">TypeError</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'subclasses works only with new-style classes'</span>
                            <span style="color: #483d8b;">', not %s'</span> <span style="color: #66cc66;">%</span> cls<span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># On va stocker les classes rencontrées dans un set</span>
    <span style="color: #808080; font-style: italic;"># pour éviter les doublons car on peut tomber sur</span>
    <span style="color: #808080; font-style: italic;"># un héritage en forme de diamant.</span>
    _found = _found <span style="color: #ff7700;font-weight:bold;">or</span> <span style="color: #008000;">set</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">try</span>:
      subs = cls.__subclasses__<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">TypeError</span>:  <span style="color: #808080; font-style: italic;"># Erreur levée si cls == type, petits vicieux</span>
      subs = cls.__subclasses__<span style="color: black;">&#40;</span>cls<span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">for</span> sub <span style="color: #ff7700;font-weight:bold;">in</span> subs:
        <span style="color: #ff7700;font-weight:bold;">if</span> sub <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #ff7700;font-weight:bold;">in</span> _found:
            _found.<span style="color: black;">add</span><span style="color: black;">&#40;</span>sub<span style="color: black;">&#41;</span>
            <span style="color: #808080; font-style: italic;"># Un appel récursif comme on les aimes</span>
            subclasses<span style="color: black;">&#40;</span>sub, _found<span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">return</span> _found</pre></div></div>

<p>Pas très compliqué, donc, si on connait les piègeounets : ça ne marche pas sur les old syle classes, et il y a un traitement spécial pour <code>type</code>. Celà dit, qui utilise encore des old styles classes ? Et franchement lister les héritiers de <code>type</code>, à par pour satisfaire sa curiosité&#8230;</p>
<p>Aller, juste pour le fun, sur un virtualenv vierge:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">for</span> x <span style="color: #ff7700;font-weight:bold;">in</span> subclasses<span style="color: black;">&#40;</span><span style="color: #008000;">object</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">print</span> x
<span style="color: #808080; font-style: italic;">## &lt;type 'callable-iterator'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;class '_abcoll.Sized'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'exceptions.EOFError'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;class '_abcoll.Mapping'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'exceptions.UnicodeWarning'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'exceptions.IOError'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'memoryview'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'code'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'exceptions.ImportWarning'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'sys.flags'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'iterator'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;class 'warnings.catch_warnings'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'exceptions.Warning'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'exceptions.EnvironmentError'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'dict'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;class 'encodings.utf_8.IncrementalEncoder'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'weakproxy'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;class '_abcoll.Iterator'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'sys.version_info'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'posix.stat_result'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'frozenset'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;class 'codecs.CodecInfo'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;class 'zipimport.ZipImportError'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'exceptions.StopIteration'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'exceptions.ImportError'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;class 'site._Printer'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'weakref'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;class '_abcoll.Sequence'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'property'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;class 'encodings.utf_8.IncrementalDecoder'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'imp.NullImporter'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'exceptions.TypeError'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'bytearray'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'int'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'exceptions.UnicodeTranslateError'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'instance'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'exceptions.BaseException'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'exceptions.SyntaxWarning'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'file'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;class '_abcoll.MappingView'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;class '_weakrefset._IterationGuard'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'exceptions.UnicodeDecodeError'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'classobj'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'exceptions.UnicodeError'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;class 'abc.abstractproperty'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'exceptions.DeprecationWarning'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'complex'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'set'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'buffer'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'generator'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'exceptions.Exception'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;class 'codecs.IncrementalDecoder'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'exceptions.UserWarning'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'staticmethod'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'exceptions.UnicodeEncodeError'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;class 'encodings.CodecRegistryError'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;class '_abcoll.MutableSequence'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;class '_abcoll.KeysView'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'cell'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'exceptions.StandardError'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'enumerate'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'exceptions.KeyboardInterrupt'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'exceptions.BufferError'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;class 'warnings.WarningMessage'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'EncodingMap'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;class 'codecs.BufferedIncrementalDecoder'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'exceptions.ValueError'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;class '_abcoll.Set'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'exceptions.MemoryError'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'exceptions.SystemExit'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'reversed'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;class '_abcoll.Hashable'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'bool'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'classmethod'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'exceptions.ReferenceError'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'exceptions.GeneratorExit'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;class '_abcoll.Container'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;class '_abcoll.ItemsView'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'xrange'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'exceptions.PendingDeprecationWarning'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'basestring'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'exceptions.SystemError'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'exceptions.ZeroDivisionError'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;class 'site.Quitter'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'long'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'NotImplementedType'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'super'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'fieldnameiterator'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;class '_abcoll.Callable'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;class '_abcoll.MutableSet'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'exceptions.ArithmeticError'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;class 'abc.ABCMeta'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'exceptions.OverflowError'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'exceptions.FutureWarning'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'sys.float_info'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'formatteriterator'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'type'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'exceptions.AssertionError'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'traceback'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'exceptions.FloatingPointError'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'function'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'instancemethod'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'sys.long_info'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'builtin_function_or_method'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;class 'signal.ItimerError'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;class 'site._Helper'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'exceptions.LookupError'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'wrapper_descriptor'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'exceptions.KeyError'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;class '_abcoll.ValuesView'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'slice'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;class '_weakrefset.WeakSet'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'list'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'exceptions.IndexError'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'getset_descriptor'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'posix.statvfs_result'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'exceptions.SyntaxError'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'frame'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;class 'codecs.BufferedIncrementalEncoder'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'PyCapsule'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'exceptions.IndentationError'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'NoneType'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'zipimport.zipimporter'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'member_descriptor'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'exceptions.AttributeError'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'ellipsis'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'exceptions.UnboundLocalError'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'unicode'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;class '_abcoll.Iterable'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'exceptions.TabError'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'exceptions.NameError'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'tuple'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;class 'warnings._OptionError'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'exceptions.NotImplementedError'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'exceptions.RuntimeWarning'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'str'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;class '_abcoll.MutableMapping'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'exceptions.BytesWarning'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'module'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'exceptions.RuntimeError'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;class 'codecs.IncrementalEncoder'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'float'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'exceptions.OSError'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'dictproxy'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;type 'weakcallableproxy'&gt;</span></pre></div></div>

<p>Putain, ça c&#8217;est du remplissage ! 20minutes serait fier de moi.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=11013&amp;md5=9198e16f2ea13b4d062b93aecc44825c" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=11050
title: Attributs privés en Python
uri: Attributs-privés-en-Python
url: http://sametmax.com/variables-privees-en-python/
content:
<p><strong>Tout est accessible en Python. Il n&#8217;y a pas de variables privées.</strong></p>
<p>Quand on veut une variable à usage interne, la convention est de la nommer avec un underscore devant :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">class</span> Monique:
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>._private = <span style="color: #483d8b;">&quot;lessons&quot;</span></pre></div></div>

<p>Ça n&#8217;empêche rien, mais les devs savent qu&#8217;il faut éviter d&#8217;utiliser cette variable car elle ne fait pas partie de l&#8217;API publique de la classe, et l&#8217;implémentation pourrait changer plus tard.</p>
<p>Comme <code>self</code>, c&#8217;est une convention forte puisque la plupart des libs de completion du code la prennent en compte.</p>
<p>Il existe une fonctionalité moins connue, qui fait que quand on utilise <strong>deux</strong> underscores, accéder directement à la variable lève un <code>AttributeError</code>:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">class</span> Monique:
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>.__private = <span style="color: #483d8b;">&quot;lessons&quot;</span>
&nbsp;
m = Monique<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>m.__private<span style="color: black;">&#41;</span>
<span style="color: #008000;">AttributeError</span>: <span style="color: #483d8b;">'Monique'</span> <span style="color: #008000;">object</span> has no attribute <span style="color: #483d8b;">'__private'</span></pre></div></div>

<p>Du coup, quelques rares personnes ont utilisé cette feature pour émuler des attributs privés, ignorant le fait qu&#8217;on vous dit partout sur la toile que tout est accessible en Python.</p>
<p>C&#8217;est une mauvaise idée.</p>
<p>C&#8217;est une mauvaise idée car si votre objectif est la sécurité, ça ne sert à rien puisque votre variable est accessible de tas de manières détournées différentes. Par exemple :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>m.<span style="color: #0000cd;">__dict__</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">'_Monique__private'</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
<span style="color: #808080; font-style: italic;"># lessons</span>
m.<span style="color: #0000cd;">__dict__</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">'_Monique__private'</span><span style="color: black;">&#93;</span> = <span style="color: #008000;">None</span>
<span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>m.<span style="color: #0000cd;">__dict__</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">'_Monique__private'</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
<span style="color: #808080; font-style: italic;"># None</span></pre></div></div>

<p>C&#8217;est une mauvaise idée car si votre objectif est de créer une API publique, un seul underscore suffit.</p>
<p>Enfin c&#8217;est une mauvaise idée car si vous fournissez une lib qui ne correspond pas à un besoin, quelqu&#8217;un peut toujours contourner le problème en monkey patchant votre code le temps que vous trouviez une solution plus propre. En rendant la variable &#8220;privée&#8221;, vous rendez ceci plus difficile, sans le rendre impossible. Tout le monde y perd.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=11050&amp;md5=5d90c65ec47a7409c17731671c438759" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=11061
title: Un petit tour des frameworks Web Python
uri: Un-petit-tour-des-frameworks-Web-Python
url: http://sametmax.com/un-petit-tours-des-frameworks-web-python/
content:
<p><a href="http://bottlepy.org/">Bottle</a> : le plus petit disponible (tient dans un fichier). Génial pour du code jetable ou des petits sites, etc. Fantastique outil d&#8217;enseignement et d&#8217;apprentissage. En plus, ça tient plutôt bien la charge compte tenu de la taille.</p>
<p><a href="https://www.djangoproject.com/">django</a> : le framework Python le plus connu. On peut tout faire avec, l’écosystème est fantastique (il y a des apps djangos tierces partout pour tout et n&#8217;importe quoi, c&#8217;est un truc de fou). Mais le maîtriser prend du temps. Efficace pour construire un site web avec beaucoup de logique personnalisée. Au final, si on veut être sérieux dans en programmation Web avec Python, on finit toujours par passer par Django.</p>
<p><a href="http://flask.pocoo.org/docs/">flask</a> : sa taille est entre django et bottle, et avec tout ce qu&#8217;il faut pour faire un site de taille moyenne. Il commence à avoir pas mal de plugins disponibles un peu partout sur la toile, et est une alternative très sympa quand on n&#8217;a pas besoin de charger les 3 tonnes de Django.</p>
<p><a href="http://web2py.com/">wep2py</a> : se positionne en alternative à Django et Flask, mais avec une philosophie très différente. Pas mal de magie (à la rails), des interfaces graphiques pour l&#8217;admin, composants très couplés mais très intégrés&#8230; Je ne suis pas fan, mais on m&#8217;en a dit du bien.</p>
<p><a href="http://docs.cherrypy.org/">cherrypy</a> : un framework WSGI pure Python qui a de très bonnes perfs sans rien rajouter, même en prod. Mais depuis qu&#8217;ils ont rendu disponible sa partie serveur et qu&#8217;on peut l&#8217;utiliser pour Django/flask/bottle, ça ne vaut plus le coup d&#8217;utiliser sa partie framework qui n&#8217;a rien de fantastique.</p>
<p><a href="http://docs.pylonsproject.org/projects/pyramid/">pyramid</a> : le plus gros compétiteur de Django en termes de fonctionnalités. Beaucoup moins monolithique, et bien plus flexible, donnant pas mal de contrôle. Mais l&#8217;intégration des composants de django le rend beaucoup plus facile à maîtriser, et son écosystème est 100 fois meilleur (j&#8217;ai toujours été en froid avec l&#8217;écosystème Zope).</p>
<p><a href="http://twistedmatrix.com/">twisted</a> un framework internet asynchrone en pur Python. J&#8217;ai dit INTERNET, pas WEB. On peut faire HTTP, mais aussi SSH, IMAP, FTP, et à peu près n&#8217;importe quoi. Surpuissant, et ses performances sont incroyables. Son API est aussi la plus merdique de tout l&#8217;univers Python. Apprendre et utiliser Twisted, c&#8217;est comme se branler avec des gants de boxe en récitant l&#8217;alphabet à l&#8217;envers.</p>
<p><a href="http://tornado.readthedocs.org/">tornado</a> : framework Web asynchrone. Techniquement le seul compétiteur de nodejs en pur Python (pas de gevent, d&#8217;extension C, etc) si on exclue crossbar encore trop immature. L&#8217;API n&#8217;est pas incroyable, mais pas trop dur, et les perfs sont bonnes. Les Websocket marchent clé en main.</p>
<p><a href="http://cyclone.io/">cyclone</a> : tornado qui tourne dans l&#8217;event loop de twisted. Pour pouvoir utiliser l&#8217;API de tornado pour le Web, mais les outils de twisted pour le reste. Si vous êtes capable d&#8217;utiliser ça à son plein potentiel, qu&#8217;est-ce que vous foutez à lire cet article ?</p>
<p><a href="http://webpy.org/">webpy</a> : un ancêtre. Un fantôme du passé. Do not use.</p>
<p>Il existe ensuite tout un tas d&#8217;expérimentations de framework avec asyncio, gevent, etc. C&#8217;est plus du bricolage qu&#8217;autre chose pour le moment, alors je ne recommande pas de base un gros projet dessus à moins d&#8217;être déjà très à l&#8217;aise avec la prog web python.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=11061&amp;md5=45ee0885b281cf798bb1b0e1662ee791" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=11073
title: Prostitution masculine
uri: Prostitution-masculine
url: http://sametmax.com/prostitution-masculine/
content:
<p>Un de mes coloc est un ancien gogo dancer, et je le soupçonne de bien plus. Mais dans les apparences, c&#8217;est un garçon très propre sur lui, et depuis quand je rencontre de nouvelles personnes, je les imagine toujours dans des situations coquines.</p>
<p>Il se trouve que quand on parle de pute, on pense généralement à des nanas, pas à des gigolos, car il y en a beaucoup moins. Enfin en France, parce que quand je travaillais en Afrique, j&#8217;en ai vu des blondes venir se payer leur bois d&#8217;ébène&#8230;</p>
<p>Cependant, il existe une prostitution bien moins reconnue : la prostitution sociale. Coucher pour réussir, pour bénéficier du train de vie d&#8217;une personne, pour éviter des ennuis, pour ne pas perdre quelque chose, en échange d&#8217;un service, d&#8217;un bien ou d&#8217;un avantage&#8230;</p>
<p>Ces putes là sont très nombreuses, parfaitement socialement acceptées, absolument pas assumées, et les mecs sont beaucoup plus représentés.</p>
<p>Non pas qu&#8217;il n&#8217;y a pas de nanas putes sociales, elles sont légions, mais je trouve qu&#8217;on a tendance à omettre trop souvent les deux côtés de la pièce. L&#8217;homme pute est là, et pas juste métaphoriquement.</p>
<p>Comme un de mes potes avocat qui a fisté son batonier car c&#8217;était bon pour sa carrière.</p>
<p>Comme un des potes de Max qui a couché régulièrement avec un thon ce mois-ci car il avait besoin de sa voiture et qu&#8217;elle garde les chiens de sa copine (sic) pendant quelques mois.</p>
<p>Et qui n&#8217;a pas dans son entourage ce type qui se force à se taper sa gonzesse dont il ne veut plus pour éviter qu&#8217;elle l&#8217;emmerde, qu&#8217;elle divorce, qu&#8217;elle prenne les enfants/l&#8217;argent, etc ?</p>
<p>On a tous des tas de gens autour de nous, hommes ou femmes, qui utilisent leur cul pour obtenir quelque chose.</p>
<p>Mais ça ne se limite pas à ça.</p>
<p>Cette semaine, en boîte, une meuf a proposé de l&#8217;argent à Max pour qu&#8217;il rentre avec elle.</p>
<p>Je suis un peu jaloux, ça ne m&#8217;est jamais arrivé.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=11073&amp;md5=2d7660a57b544651740f0a4a39a8f8cd" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=11078
title: Pourquoi sametmax.com utilise WordPress ?
uri: Pourquoi-sametmax-com-utilise-WordPress
url: http://sametmax.com/pourquoi-sametmax-com-utilise-wordpress/
content:
<blockquote><p>WordPress est le pire des blog engines, à l&#8217;exception de tous les autres</p></blockquote>
<p><em>Churchill</em></p>
<h2>Il y a des solutions en Python, pourquoi vous ne les utilisez pas ?</h2>
<p>Parce que c&#8217;est trop de taff. Si on veut une feature, il faudra la coder puisque ces blogs n&#8217;ont pas de communauté de plugins qui approche 1/1000eme de celle de WordPress. </p>
<p>Par exemple, depuis l&#8217;ouverture du blog, on a installé 3 plugins anti-spam, un plugin pour adapter Varnish, un pour avoir des stats sans Google analytics, un formulaire de contact, un live preview pour les commentaires, un outil de notes collaboratives, etc. On a aussi changé 10 fois de thèmes, et custo celui-là à mort (je sais, il est moche :)).</p>
<p>Je ne connais aucune solution de blog <strong>Python ou non</strong> qui permette de faire tout ça out of the box.</p>
<p>Or, durant ces 2 dernières années, on a publié plus de 742 articles. Pas un article par jour, mais pas loin. On a une vie assez remplie également derrière. Et même si on a la chance de pouvoir gérer notre emploi du temps, ce dont on use et abuse, les journées n&#8217;ont que 37h.</p>
<h2>Je connais un super générateur de blog statique qui&#8230;</h2>
<p>Pas de commentaires indexable par Google. Pas de formulaire de contact. Besoin de connaître un VCS pour les contributeurs. Pas de gestion de droits&#8230; J&#8217;ai failli rajouter pas de moteur de recherche mais c&#8217;est vrai que le notre est pourri.</p>
<h2>Pourquoi pas une plateforme en ligne alors ?</h2>
<p>On veut avoir le contrôle de nos données pour éviter de se faire fermer violemment en cas de problème.</p>
<h2>Ok, mais pourquoi pas Dotclear, Ghost, etc ?</h2>
<p>J&#8217;en ai  essayé par mal. Aucun n&#8217;a le nombre de plugins et thèmes de WordPress. Aucun n&#8217;a autant de features. Aucun n&#8217;a autant de tutos. Et rien ne prouve qu&#8217;on aura moins de problèmes avec.</p>
<p>Tout va toujours bien jusqu&#8217;à ce qu&#8217;on dépasse 10 visiteurs par jour.</p>
<h2>Alors arrêtez de vous plaindre !</h2>
<p>Si tu ne veux pas nous entendre nous plaindre, ne nous lis pas. Il y a un petit bouton en forme de croix en haut à droite de ton tab, tu vas voir, c&#8217;est magique.</p>
<h2>Sinon, pas envie de coder votre solution ?</h2>
<p>Très envie. Mais contrairement à la plupart des gens, je ne pense pas que créer un moteur de blog ce soit &#8220;3 jours de boulot&#8221;.</p>
<p>C&#8217;est un taff énorme, et là, tout de suite, c&#8217;est mort.</p>
<p>Et il existe 20000 personnes qui en ont fait un, donc pour avoir une raison de coder quelque chose, il faudrait faire quelque chose de vraiment innovant :</p>
<ul>
<li>Une plateforme qui fasse blog + shaarly + microblogging.</li>
<li>L&#8217;éditeur ressemble à celui de ghost, mais part du principe que le mec aux commandes sait ce qu&#8217;il fait (on n&#8217;empêche pas les iframes, le HTML sensible, etc).</li>
<li>Même éditeur pour les articles, les liens et les microblogs.</li>
<li>Si on poste moins de 140 chars => microblog automatique. Cross posté sur twitter ou autre.</li>
<li>Première ligne est un lien => shaarly.</li>
<li>Sinon c&#8217;est un article.</li>
<li>Pas de categ, uniquement des tags : #microblog, #link, #article et ceux que l&#8217;auteur met. Pas de truc compliqué, tagger c&#8217;est juste mettre #mot dans le corps du post. #tag link automatiquement sur une liste des posts avec tous ces tags.</li>
<li>Un moteur de recherche qui ne soit pas inutile.</li>
<li>Anti spam intégré et efficace.</li>
<li>Tout est en Markdown, même les commentaires. Possibilité de faire un @mention dans les commentaires, comme dans Discourse</li>
<li>RSS pour tout : tags, commentaires, recherche&#8230;</li>
<li>Toute page est visible en JSON.</li>
<li>API de post en JSON.</li>
<li>API de migrations/synchronisation de blog d&#8217;un serveur à l&#8217;autre en JSON. Si on veut changer d&#8217;hébergeur, on peut juste setuper un nouveau blog, le linker au précédent, et attendre qu&#8217;il se synchro, puis basculer le nom de domaine.</li>
<li>Versioning des articles et des commentaires.</li>
<li>Versioning du code du blog, notamment les modifs manuelles des thèmes.</li>
<li>Cron jobs intégrés pour les opérations longues.</li>
<li>Cache in memory intégré pour qu&#8217;on puisse survivre à sebsauvage sans avoir à mettre varnish.</li>
<li>Auto backup régulier.</li>
<li>Dump statique du blog généré automatiquement et disponible en téléchargement.</li>
<li>Tous les articles sont téléchargebles en Markdown et en PDF.</li>
<li>Un bouton &#8220;Dire merci&#8221; en bas du blog qui ouvre une fenêtre modale. Propose flattr, bitcoin, gittip, des liens perso, et juste un bouton &#8220;dire seulement merci&#8221; qui fait une notif dans l&#8217;admin. Pas besoin de laisser un commentaire pour ça, mais ça remonte le moral.</li>
<li>Un bouton share qui ouvre une modale avec tous les boutons de partage de réseaux sociaux. Si on ne clique pas dessus, ils ne sont pas chargés ni visibles.</li>
<li>Un bouton &#8220;proposez une amélioration&#8221; qui permet à un lecteur de modifier l&#8217;article (par exemple pour corriger l&#8217;orthographe), et on reçoit le diff dans l&#8217;admin qu&#8217;on peut merger. Si on merge, une ligne crédite le lecteur dans les commentaires.</li>
<li>Un système de ressources externes (images, videos, etc) qui permet de mettre un lien source qui apparaît en hover. Si on donne l&#8217;URL de la ressource, des metadata sont pullées automatiquement. Sinon, on peut tagger manuellement la ressource. On peut chercher efficacement toutes les ressources et par exemple répondre à une question du type &#8220;est-ce que j&#8217;ai déjà posté ça&#8221; ?</li>
<li>Un form d&#8217;upload d&#8217;image décent qui permet de DL depuis une URL ou le disque et modifier l&#8217;image inplace pour faire des crops, rotates, etc.</li>
<li>Un réseau entre tous les utilisateurs du blog qui peuvent s&#8217;ajouter et se follow comme sur dispora.</li>
<li>Une version mobile intégrée.</li>
<li>Un lecteur de PDF et de video intégré.</li>
<li>De l&#8217;autocompletion partout.</li>
<li>Articles multilingues.</li>
<li>Un chat intégré, discret, avec autocompletion sur les articles du blog, un système de quote, d&#8217;embed de media, etc.</li>
<li>Un formulaire de contact propre, simple, qui marche.</li>
<li>Un système de droits intégré mais simple pour gérer les contributeurs.</i>
<li>Un système de comment interne pour toutes les pages d&#8217;admin et les articles. Sérieux, pourquoi c&#8217;est pas en standard partout ?</li>
<li>Un système de chat interne.</li>
<li>Les articles peuvent s&#8217;éditer en mode colaboratif comme dans etherpad, au lieu de s&#8217;écraser mutuellement la gueule.</li>
<li>Pas de features inutiles comme un champ de recherche in page (sérieusement, WordPress, CTRL+F ça sert à quoi ?) ou de correction orthographique (ghost, mon browser le fait déjà, mon éditeur le fait déjà, Open Office le fait déjà, et ça ne change rien).</li>
<li>Le blog peut s&#8217;installer ainsi : DL, unzip, run. Rien d&#8217;autre à faire.</li>
<li>Un scrap book intégré pour y mettre les ressources qu&#8217;on veut utiliser pour ses publications futures.</li>
<li>Analytics basique intégré.</li>
<li>Edition facile des thèmes in browser. Avec un éditeur décent, type ACE, et une gestion du versioning avec diff et rollback.</li>
<li>Console qui permet d&#8217;obtenir un shell donnant accès au code du blog, à la base de données, etc. Typiquement sur un blog en Python, ce serait un remote IPython avec l&#8217;ORM préchargé. Pour toutes ces fois où je voulais faire un truc one shot que WordPress permettait pas et qui aurait été si facile à faire à la main. Évidement, ne pourrait marcher que si SSL est activé ou qu&#8217;on a installé une extension navigateur pour faire de l&#8217;OTR car en pure JS, c&#8217;est mort.</li>
</ul>
<p>Ça, ça serait un truc qui vaudrait le coup de se faire chier à migrer dessus.</p>
<p>3 jours de dev ? Mouarf. Comptez plutôt 3 ans, pendant tous ces jours de libre. Autant dire que ça n&#8217;arrivera pas.</p>
<p>Bref, je vous laisse vous référer à l&#8217;image d&#8217;illustration de l&#8217;article pour résumer la situation des bloggers sur la toile actuellement.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=11078&amp;md5=7b1ca71ff10888295a9f4397874bb1f6" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=10327
title: D’une base à l’autre en Python
uri: D-une-base-à-l-autre-en-Python
url: http://sametmax.com/dune-base-a-lautre-en-python/
content:
<p>Je vous avais parlé <a href="http://sametmax.com/la-fin-du-mystere-du-binaire-nananere/">des bases</a> dans l&#8217;article sur le binaire. En informatique, on utilise essentiellement la base 10, évidement, mais aussi 2, 8, 16 et 64. Des puissances de 2, quoi.</p>
<p>Cependant, il arrive parfois qu&#8217;on ait besoin d&#8217;une base personalisée. En effet, une base n&#8217;étant qu&#8217;une notation, on peut en créer une de toutes pièces. C&#8217;est parfois très utile :</p>
<ul>
<li>Besoin de limiter au maximum le nombre de caractères pour représenter une donnée. Si la base 64 ne suffit pas, on créera des bases 70, voire plus si on a accès à un charset large.</li>
<li>On est limité dans les caractères qu&#8217;on peut utiliser. Typiquement dans certains formulaires de mots de passe, on a le droit qu&#8217;à <code>-_</code>, des lettres et des chiffres.</li>
<li>On souhaite limiter les caractères à utiliser. Ça m&#8217;est arrivé en travaillant sur un système à base de SMS. Les ID devaient éviter de contenir tous les caractères comme <code>1, l, 0, O, S, 5, Z, 2</code> car trop faciles à confondre sur un nokia 3310.</li>
</ul>
<p>Mais la plupart des outils ne permettent pas de choisir la base de représentation des données qu&#8217;ils génèrent. Pour cette raison, il peut être pratique d&#8217;implémenter une petit convertisseur d&#8217;une base à l&#8217;autre.</p>
<p>Voici un objet Python qui permet de convertir une string d&#8217;une base custom en entier en base 10, et inversement.</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># Il est possible de passer de n'importe quelle base à</span>
<span style="color: #808080; font-style: italic;"># une autre directement, mais utiliser la base 10,</span>
<span style="color: #808080; font-style: italic;"># comme pivot, est ce qu'il y a de plus facile </span>
<span style="color: #808080; font-style: italic;"># à coder</span>
<span style="color: #ff7700;font-weight:bold;">class</span> BaseConverter:
&nbsp;
   <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, symboles<span style="color: black;">&#41;</span>:
      <span style="color: #008000;">self</span>.<span style="color: black;">symboles</span> = symboles
      <span style="color: #008000;">self</span>.<span style="color: black;">sym2val</span> = <span style="color: black;">&#123;</span>l: i <span style="color: #ff7700;font-weight:bold;">for</span> i, l <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">enumerate</span><span style="color: black;">&#40;</span>symboles<span style="color: black;">&#41;</span><span style="color: black;">&#125;</span>
      <span style="color: #008000;">self</span>.<span style="color: black;">val2sym</span> = <span style="color: #008000;">dict</span><span style="color: black;">&#40;</span><span style="color: #008000;">enumerate</span><span style="color: black;">&#40;</span>symboles<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
   <span style="color: #ff7700;font-weight:bold;">def</span> to_base_10<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, <span style="color: #dc143c;">string</span><span style="color: black;">&#41;</span>:
       i = <span style="color: #ff4500;">0</span>
       base = <span style="color: #008000;">len</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">sym2val</span><span style="color: black;">&#41;</span>
       <span style="color: #808080; font-style: italic;"># On part de la gauche vers la droite,</span>
       <span style="color: #808080; font-style: italic;"># donc on commence avec les valeurs les plus</span>
       <span style="color: #808080; font-style: italic;"># grosses.</span>
       <span style="color: #808080; font-style: italic;"># Pour chaque symbole, on ajoute la valeur</span>
       <span style="color: #808080; font-style: italic;"># de celui-ci (donnée par la table) et</span>
       <span style="color: #808080; font-style: italic;"># avec facteur lié à sa position.</span>
       <span style="color: #ff7700;font-weight:bold;">for</span> c <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #dc143c;">string</span>:
           i <span style="color: #66cc66;">*</span>= base
           i += <span style="color: #008000;">self</span>.<span style="color: black;">sym2val</span><span style="color: black;">&#91;</span>c<span style="color: black;">&#93;</span>
       <span style="color: #ff7700;font-weight:bold;">return</span> i
&nbsp;
   <span style="color: #ff7700;font-weight:bold;">def</span> from_base_10<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, number<span style="color: black;">&#41;</span>:
       <span style="color: #483d8b;">&quot;&quot;&quot; Convert from a base 10 to the custom base&quot;&quot;&quot;</span>
       <span style="color: #dc143c;">array</span> = <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>
       base = <span style="color: #008000;">len</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">val2sym</span><span style="color: black;">&#41;</span>
       <span style="color: #808080; font-style: italic;"># Division euclidienne en boucle jusqu'à ce que le</span>
       <span style="color: #808080; font-style: italic;"># reste soit égal à zero.</span>
       <span style="color: #ff7700;font-weight:bold;">while</span> number:
           number, value = <span style="color: #008000;">divmod</span><span style="color: black;">&#40;</span>number, base<span style="color: black;">&#41;</span>
           <span style="color: #808080; font-style: italic;"># Le résultat est l'index du symbole.</span>
           <span style="color: #808080; font-style: italic;"># On le place le plus à gauche, chaque</span>
           <span style="color: #808080; font-style: italic;"># symbole ayant une valeur plus grande</span>
           <span style="color: #808080; font-style: italic;"># que le précédent.</span>
           <span style="color: #dc143c;">array</span>.<span style="color: black;">insert</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span>, <span style="color: #008000;">self</span>.<span style="color: black;">val2sym</span><span style="color: black;">&#91;</span>value<span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
&nbsp;
       <span style="color: #808080; font-style: italic;"># Ne pas oublier le zéro</span>
       <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #483d8b;">''</span>.<span style="color: black;">join</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">array</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">or</span> <span style="color: #008000;">self</span>.<span style="color: black;">symboles</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span></pre></div></div>

<p>Maintenant imaginez la génération d&#8217;un UUID qui doit seulement contenir certains caractères ou avoir une certaine taille. Par exemple, votre client vous demande des ID en <a href="http://www.crockford.com/wrmg/base32.html">base 32 de Crockford</a>.</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">uuid = uuid.<span style="color: black;">uuid4</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>uid<span style="color: black;">&#41;</span>
<span style="color: #808080; font-style: italic;">## 50ab7fa9-9643-4aad-be84-548405abea08</span>
CROCKFORD_B32 = BaseConverter<span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;0123456789abcdefghjkmnpqrstvwxyz&quot;</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>CROCKFORD_B32.<span style="color: black;">from_base_10</span><span style="color: black;">&#40;</span>uid.<span style="color: #008000;">int</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #808080; font-style: italic;">## 2gndztk5j39apvx12mgg2tqtg8</span></pre></div></div>

<p>Bon, évidément, pour toutes les bases ordinaires, <code>int(string, base)</code> fait ça très bien.</p>
<p>On peut aller plus loin et faire une seule partie de l&#8217;ID dans une base, et l&#8217;autre dans une autre base, pour des raisons de lisibilité. Le cas d&#8217;école étant les plaques d&#8217;immatriculation ou les numéros de vol.</p>
<p>Une fois, on m&#8217;a demandé de faire une URL de type :</p>
<p><code>/ressource/id/</code></p>
<p>Mais l&#8217;id devait être facile à recopier à la main. Le client a opté pour une notation de type &#8220;AAA111&#8243;, 3 lettres, puis 3 chiffres.</p>
<p>Vu qu&#8217;il fallait l&#8217;implémenter en Lua embed dans nginx, la solution la plus simple a été adoptée :</p>

<div class="wp_syntax"><div class="code"><pre class="ini" style="font-family:monospace;">location ~ <span style="color: #933;">&quot;^/([0-9A-Fa-f]{3}[0-9]{3})$&quot;</span> <span style="">&#123;</span>
   set $short_id $1<span style="color: #666666; font-style: italic;">;</span>
   content_by_lua '
       local redirect_url <span style="color: #000066; font-weight:bold;">=</span> <span style="color: #933;">&quot;http://site.com/ressource/&quot;</span> .. string.sub<span style="">&#40;</span>ngx.var.short_id, -<span style="">3</span><span style="">&#41;</span> + tonumber<span style="">&#40;</span>string.sub<span style="">&#40;</span>ngx.var.short_id,<span style="">0</span>,<span style="">3</span><span style="">&#41;</span>, <span style="">16</span> <span style="">&#41;</span> * <span style="">1000</span>
       return ngx.redirect<span style="">&#40;</span>redirect_url..<span style="color: #933;">&quot;/&quot;</span><span style="">&#41;</span>
   '<span style="color: #666666; font-style: italic;">;</span>
<span style="">&#125;</span></pre></div></div>

<p>En gros, on prend les 3 premiers caractères, on les traite comme de l&#8217;hexa, puis on multiplie par 999, et on additionne les 3 derniers chiffres. Cela convertit le truc en base 10.</p>
<p>L&#8217;URL est très lisible, et facile à dicter ou recopier à la main :</p>
<p><code>http://site.com/ressource/FAC101</code></p>
<p>Bien entendu, on peut se retrouver avec des chiffres au début puisque c&#8217;est de l&#8217;hexa, et avoir une URL de type <code>345823</code>, mais ça a été accepté.</p>
<p>Au maximum on ne peut gérer que 4 millions d&#8217;ID. Or le site n&#8217;en avait pas accumulé plus de 350 000 en 7 ans, et à moins que le trafic explose soudainement (auquel cas il aura le budget pour me payer pour changer l&#8217;algo:)), ça devrait tenir 80 ans.</p>
<p>Je vais sans doute ajouter ce code à <a href="https://github.com/sametmax/Bat-belt/tree/master/batbelt">Batbelt</a> du coup.</p>
<hr />
<p><a href="https://github.com/sametmax/codes-des-articles/blob/master/2014/juin/base.py">Télécharger le code de l&#8217;article</a></p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=10327&amp;md5=2085afe76bac505b7451cd7b00784248" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=11146
title: Petite démo pragmatique d’un usage de WAMP en Python
uri: Petite-démo-pragmatique-d-un-usage-de-WAMP-en-Python
url: http://sametmax.com/introduction-a-wamp-en-python/
content:
<p>Vu que dernièrement je vous ai bien gavé avec <a href="http://sametmax.com/crossbar-le-futur-des-applications-web-python/">WAMP</a>, ça mérite un tuto non ?</p>
<p>Il se trouve que l&#8217;équipe derrière WAMP a publié plus tôt que prévu une version de leurs libs contenant l&#8217;API flaskesque sur laquelle on bosse. L&#8217;idée est que même si on n&#8217;a pas encore les tests unitaires, on peut déjà jouer avec.</p>
<p>Maintenant il me fallait un projet sexy, histoire de donner envie. Donc j&#8217;ai fouillé dans ce qui se faisait côté temps réel (essentiellement du NodeJS et du Tornado, mais pas que) pour trouver l&#8217;inspiration.</p>
<p>Et j&#8217;ai trouvé un truc très sympa : <a href="http://news.softpedia.com/news/YouTube-Will-Turn-Your-Phone-into-a-Smart-TV-Remote-318286.shtml">un player vidéo piloté à distance.</a></p>
<p>En effet, n&#8217;est-il pas chiant de regarder une vidéo en ligne sur son ordi posé sur la commode pendant qu&#8217;on est enfoncé dans le canap ? Si on veut faire pause ou changer le son, il faut se lever, arg.</p>
<p>Les problèmes du tiers monde, c&#8217;est du pipi de chat à côté. Ils ont de la chance, eux, ils ne connaissent pas le streaming.</p>
<p><strong>Voici donc le projet : </strong></p>
<p>Une page avec un player HTML 5 et un QR code.</p>
<div id="attachment_11151" class="wp-caption aligncenter" style="width: 335px"><a href="media/c002902c.video.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/06/video.png"><img src="media/c002902c.video.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/06/video.png" alt="Capture d&#039;écran de la démo, côté player" title="Pour simplifier la démo, on peut cliquer sur le QR code est avoir la télécommande dans un autre tab pour ceux qui n&#039;ont pas de smartphone ou d&#039;app de scan de QRCode." width="325" height="186" class="size-full wp-image-11151" /></a><p class="wp-caption-text">Pour simplifier la démo, on peut cliquer sur le QR code et avoir la télécommande dans un autre tab pour ceux qui n&#039;ont pas de smartphone ou d&#039;app de scan de QRCode.</p></div>
<p>Si on scanne le QR code avec son téléphone, il vous envoie sur une page avec une télécommande pour contrôler le player sans bouger votre cul :</p>
<div id="attachment_11152" class="wp-caption aligncenter" style="width: 306px"><a href="media/27ddbc4e.controles.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/06/controles.png"><img src="media/27ddbc4e.controles.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/06/controles.png" alt="Capture d&#039;écrand de la démo, côté contrôles" title="Évidement, c&#039;est basique. Je vais pas m&#039;amuser à faire un produit complet juste pour un truc dont le code source ne sera même pas regardé par la plupart d&#039;entre vous. Je vous connais, bandes de feignasses !" width="296" height="370" class="size-full wp-image-11152" /></a><p class="wp-caption-text">Évidement, c&#039;est basique. Je vais pas m&#039;amuser à faire un produit complet juste pour un truc dont le code source ne sera même pas regardé par la plupart d&#039;enter vous. Je vous connais, bandes de feignasses !</p></div>
<p>Et vous allez voir, c&#8217;est même pas dur à faire. </p>
<p>Mais d&#8217;abord :</p>
<p style="margin:1em; text-align:center">
<a style="font-size:2em;" href="https://demo.crossbar.io/videocontrol/">La démo</a>
  </p>
<p>Bon, y a plus de latence que je le voudrais, mais sur un projet sérieux, il y a moyen de faire ça mieux. Ici on veut faire simple pour expliquer le principe.</p>
<p><a href="https://github.com/sametmax/codes-des-articles/tree/master/2014/juin/video_remote">Et vous pouvez télécharger le code ici</a>.</p>
<p>Pour comprendre ce qui va suivre, il va vous falloir les bases en prog Javascript et Python, ainsi que bien comprendre la notion de <a href="http://sametmax.com/quest-ce-quun-callback/">callback</a>. Être à l&#8217;aise avec <a href="http://sametmax.com/deferred-future-et-promise-le-pourquoi-le-comment-et-quand-est-ce-quon-mange">promises</a> peut aider.</p>
<p>Et pour bien digérer ce paté, rien ne vaut un peu de son :</p>

<!-- iframe plugin v:2.3 - wordpress.org/extend/plugins/iframe/ -->
<iframe width="560" height="315" src="//www.youtube.com/embed/FU4cnelEdi4" frameborder="0" scrolling="no" class="iframe-class"></iframe>
<h2>Le Chteumeuleu</h2>
<p>Il va nous falloir deux pages Web, une pour le player video, et une pour la télécommande.</p>
<p>Le player :</p>

<div class="wp_syntax"><div class="code"><pre class="html" style="font-family:monospace;">&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
   &lt;title&gt;Video&lt;/title&gt;
   &lt;meta charset='utf-8'&gt;
   &lt;!-- Chargement des dépendances : autobahn pour WAMP
   et qrcode pour générer le QR code. Bien entendu, je
   vous invite à ne pas les hotlinker dans vos projets,
   mais pour la démo c'est plus simple. --&gt;
  &lt;script src=&quot;https://autobahn.s3.amazonaws.com/autobahnjs/latest/autobahn.min.jgz&quot;
         type=&quot;text/javascript&quot;&gt;&lt;/script&gt;
   &lt;script src=&quot;http://davidshimjs.github.com/qrcodejs/qrcode.min.js&quot;
           type=&quot;text/javascript&quot;&gt;&lt;/script&gt;
&nbsp;
   &lt;style type=&quot;text/css&quot;&gt;
      /* Quelques styles histoire que ça soit pas
         TROP moche. J'inline, hein, on va pas
         se faire chier à faire un fichier CSS
         externe juste pour ça. */
      #vid {
         /* Taille de la video */
         width:427px;
         height:240px;
      }
      /* Centrage avec la méthode Rache */
      #container {
          width:427px;
          margin:auto;
      }
      #ctrllink {
          display:block;
          width:256px;
          margin:auto;
      }
   &lt;/style&gt;
&nbsp;
&lt;/head&gt;
&lt;body&gt;
&lt;div id=&quot;container&quot;&gt;
  &lt;p&gt;
&nbsp;
   &lt;!-- J'utilise le lecteur video HTML5 car c'est le plus facile
        à faire. Je ne vais pas m'attarder sur comment ça
        marche, y a plein de tutos pas trop mauvais
        sur la question --&gt;
    &lt;video id=&quot;vid&quot;
           class=&quot;video-js vjs-default-skin&quot;
           controls preload=&quot;auto&quot;
           poster=&quot;http://media.w3.org/2010/05/sintel/poster.png&quot; &gt;
&nbsp;
      &lt;!-- Encore une fois, je hotlink la video, mais ne faites
       pas ça à la maison les enfants. Surtout que les perfs du
      serveur du W3C sont merdiques et ça bufferise à mort. --&gt;
       &lt;source id='ogv'
         src=&quot;http://media.w3.org/2010/05/sintel/trailer.ogv&quot;
         type='video/ogg'&gt;
       &lt;source id='mp4'
         src=&quot;http://media.w3.org/2010/05/sintel/trailer.mp4&quot;
         type='video/mp4'&gt;
       &lt;source id='webm'
         src=&quot;http://media.w3.org/2010/05/sintel/trailer.webm&quot;
         type='video/webm'&gt;
    &lt;/video&gt;
  &lt;/p&gt;
  &lt;!-- Un élément vide pour le QR code --&gt;
  &lt;p&gt;
    &lt;a id=&quot;ctrllink&quot; href=&quot;#&quot; target=&quot;_blank&quot;&gt;
      &lt;span id=&quot;qrcode&quot;&gt;&lt;/span&gt;
    &lt;/a&gt;
  &lt;/p&gt;
 &lt;/div&gt;
&nbsp;
&lt;/body&gt;
&lt;/html&gt;</pre></div></div>

<p>Et la télécommande :</p>

<div class="wp_syntax"><div class="code"><pre class="html" style="font-family:monospace;">&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
  &lt;title&gt;Télécommande&lt;/title&gt;
  &lt;meta charset='utf-8'&gt;
  &lt;script src=&quot;https://autobahn.s3.amazonaws.com/autobahnjs/latest/autobahn.min.jgz&quot;
         type=&quot;text/javascript&quot;&gt;&lt;/script&gt;
  &lt;!-- Zoom du viewport sur mobile pour éviter d'avoir
       à le faire à la main. --&gt;
  &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1&quot;&gt;
  &lt;style type=&quot;text/css&quot;&gt;
    #controls {
      width:350px;
      margin:auto;
    }
    #controls button {
      font-size: 1em;
    }
    #controls input {
      vertical-align:middle;
       width: 200px;
       height:20px;
   }
  &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
  &lt;p id=&quot;controls&quot;&gt;
    &lt;!-- Marrant de se dire qu'en 2000, le JS inline était
         considéré comme démoniaque, et maintenant avec
         angularjs et cie, c'est exactement ce que tout
         le monde fait...
         Bref, on attache le clic sur nos contrôles à des
         méthodes de notre objet qui va se charger de la
         logique. --&gt;
&nbsp;
    &lt;button id=&quot;play&quot; onclick=&quot;control.togglePlay()&quot;&gt;Play&lt;/button&gt;
    &lt;input id=&quot;volume&quot;
                    onchange=&quot;control.volume(this.value)&quot;
                    type=&quot;range&quot;&gt;
  &lt;/p&gt;
&lt;/body&gt;
&lt;/html&gt;</pre></div></div>

<p>Rien d&#8217;incroyable. C&#8217;est du HTML, un peu de CSS, on charge les dépendances en JS. Classique.</p>
<p>Vu qu&#8217;on utilise des ressources hotlinkées par souci de simplicité, <strong>il vous faudra être connecté à Internet.</strong></p>
<h2>Setup du serveur</h2>
<p>On va travailler avec Python 2.7. Je sais, je sais, c&#8217;est pas idéal, mais pour le moment je n&#8217;ai fait l&#8217;API flaskesque que pour le backend twisted, qui est en 2.7. On ne peut pas tout faire. Est-ce que vous savez le temps que me prend juste la rédaction de ce tuto, sérieux ?</p>
<p>Bref, il nous faut avant tout un serveur HTTP pour servir nos fichiers  HTML. Normalement crossbar peut le faire pour nous en prod, mais en dev, on va pas setuper crossbar, on va faire plus simple.</p>
<p>Donc, à la racine du projet, lancez la commande :</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">python <span style="color: #660033;">-m</span> SimpleHTTPServer</pre></div></div>

<p>Vos pages Web seront ainsi servies en local sur le port 8000. Par exemple, pour afficher la page de video :</p>
<p><code>http:localhost:8000/index.html</code></p>
<p>Ensuite, faut installer de quoi faire du WAMP en Python avec <a href="http://sametmax.com/votre-python-aime-les-pip/">pip</a> :</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">pip <span style="color: #c20cb9; font-weight: bold;">install</span> <span style="color: #ff0000;">&quot;autobahn[twisted]&quot;</span></pre></div></div>

<p>Pour simplifier le développement, notre app Python va lancer automatiquement un petit serveur WAMP, du coup pas besoin d&#8217;installer crossbar du tout pour cette démo.</p>
<h2>Création de l&#8217;App WAMP côté serveur</h2>
<p>Pour cette démo, le serveur n&#8217;a pas grand chose à faire. On pourrait en fait la faire sans aucun code serveur, mais ça va nous simplifier la vie.</p>
<p>En effet, on a deux problématiques que le serveur va résoudre facilement pour nous : <strong>créer un ID unique pour le player et récupérer l&#8217;IP sur le réseau local.</strong></p>
<p>L&#8217;ID, c&#8217;est simplement que si plusieurs personnes lancent en même temps un player, on ne veut pas que les télécommandes puissent lancer un ordre à un autre player que le sien. On pourrait utiliser un timestamp, mais ils sont contiguës, n&#8217;importe quel script kiddies pourrait faire un script pour foutre la merde. On va donc créer un ID unique qui ne soit pas facilement prévisible. Javascript n&#8217;a rien pour faire ça en natif, et c&#8217;est un peu con de charger une lib de plus pour ça alors que Python peut le faire pour nous.</p>
<p>L&#8217;IP, c&#8217;est parce qu&#8217;il faut donner l&#8217;adresse de notre machine au téléphone qui va l&#8217;afficher sur la télécommande, puisque notre serveur tourne dessus. Sinon notre démo ne marchera pas. Bien sûr, en prod, on ne fera pas ça, mais en local, il faut faire avec les moyens du bord.</p>
<p>Cela veut dire aussi que le téléphone doit être sur le même réseau local pour que ça fonctionne. <strong>Donc mettez votre téléphone en Wifi, par en 3G.</strong></p>
<p>Voilà ce que donne notre code WAMP côté serveur :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># -*- coding: utf-8 -*-</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">from</span> autobahn.<span style="color: black;">twisted</span>.<span style="color: black;">wamp</span> <span style="color: #ff7700;font-weight:bold;">import</span> Application
&nbsp;
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">socket</span>
<span style="color: #ff7700;font-weight:bold;">import</span> uuid
&nbsp;
<span style="color: #808080; font-style: italic;"># Comme pour flask, l'objet app</span>
<span style="color: #808080; font-style: italic;"># est ce qui lie tous les éléments</span>
<span style="color: #808080; font-style: italic;"># de notre code ensemble. On lui donne</span>
<span style="color: #808080; font-style: italic;"># un nom, ici &quot;demo&quot;</span>
app = Application<span style="color: black;">&#40;</span><span style="color: #483d8b;">'demo'</span><span style="color: black;">&#41;</span>
<span style="color: #808080; font-style: italic;"># Bien que l'app va démarrer un serveur</span>
<span style="color: #808080; font-style: italic;"># pour nous, l'app est bien un CLIENT</span>
<span style="color: #808080; font-style: italic;"># du serveur WAMP. Le serveur démarré</span>
<span style="color: #808080; font-style: italic;"># automatiquement n'est qu'une facilité</span>
<span style="color: #808080; font-style: italic;"># pour le dev. En prod on utiliserait</span>
<span style="color: #808080; font-style: italic;"># crossbar.</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Juste un conteneur pour y mettre notre IP</span>
app._data = <span style="color: black;">&#123;</span><span style="color: black;">&#125;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># On déclare que cette fonction sera appelée</span>
<span style="color: #808080; font-style: italic;"># quand l'app se sera connectée au serveur WAMP.</span>
<span style="color: #808080; font-style: italic;"># Ceci permet de lancer du code juste après</span>
<span style="color: #808080; font-style: italic;"># le app.run() que l'on voit en bas du fichier.</span>
<span style="color: #808080; font-style: italic;"># '_' est une convention en Python pour dire</span>
<span style="color: #808080; font-style: italic;"># &quot;ce nom n'a aucune importance, c'est du code</span>
<span style="color: #808080; font-style: italic;"># jetable qu'on utilisera une seule fois&quot;.</span>
@app.<span style="color: #dc143c;">signal</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'onjoined'</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> _<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
   <span style="color: #808080; font-style: italic;"># On récupère notre adresse IP sur le réseau local</span>
   <span style="color: #808080; font-style: italic;"># C'est une astuce qui demande de se connecter et donc</span>
   <span style="color: #808080; font-style: italic;">#  à une IP externe, on a besoin d'une connexion internet.</span>
   s = <span style="color: #dc143c;">socket</span>.<span style="color: #dc143c;">socket</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">socket</span>.<span style="color: black;">AF_INET</span>, <span style="color: #dc143c;">socket</span>.<span style="color: black;">SOCK_DGRAM</span><span style="color: black;">&#41;</span>
   s.<span style="color: black;">connect</span><span style="color: black;">&#40;</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;8.8.8.8&quot;</span>, <span style="color: #ff4500;">80</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
   <span style="color: #808080; font-style: italic;"># On stocke l'adresse IP locale dans un conteneur</span>
   <span style="color: #808080; font-style: italic;"># qui sera accessible partout ailleur.</span>
   app._data<span style="color: black;">&#91;</span><span style="color: #483d8b;">'LOCAL_IP'</span><span style="color: black;">&#93;</span> = s.<span style="color: black;">getsockname</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span>
   s.<span style="color: black;">close</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># On déclare que la fonction &quot;ip()&quot; est appelable</span>
<span style="color: #808080; font-style: italic;"># via RCP. Ce qui veut dire que tout autre client</span>
<span style="color: #808080; font-style: italic;"># WAMP peut obtenir le résultat de cette fonction.</span>
<span style="color: #808080; font-style: italic;"># Donc on va pouvoir l'appeler depuis notre navigateur.</span>
<span style="color: #808080; font-style: italic;"># Comme notre app s'appelle &quot;demo&quot; et notre fonction</span>
<span style="color: #808080; font-style: italic;"># s'appelle &quot;ip&quot;, un client pourra l'appeler en faisant</span>
<span style="color: #808080; font-style: italic;"># &quot;demo.ip&quot;.</span>
@app.<span style="color: black;">register</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> ip<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
   <span style="color: #808080; font-style: italic;"># On ne fait que retourner l'IP locale. Rien de fou.</span>
   <span style="color: #ff7700;font-weight:bold;">return</span> app._data<span style="color: black;">&#91;</span><span style="color: #483d8b;">'LOCAL_IP'</span><span style="color: black;">&#93;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Je voulais appeler cette fonction distante &quot;uuid&quot;, mais ça</span>
<span style="color: #808080; font-style: italic;"># override le module Python uuid. Ce n'est pas une bonne</span>
<span style="color: #808080; font-style: italic;"># idée. Je l'appelle donc 'get_uuid' mais je déclare le</span>
<span style="color: #808080; font-style: italic;"># namespace complet dans register(). Un client WAMP pourra donc</span>
<span style="color: #808080; font-style: italic;"># bien l'appeler via &quot;demo.uuid&quot;.</span>
<span style="color: #808080; font-style: italic;"># Notez que ce namespace doit toujours s'écrire</span>
<span style="color: #808080; font-style: italic;"># truc.machine.bidule. Pas truc/machin ou truc:machin.</span>
<span style="color: #808080; font-style: italic;"># ou truc et bidule.MACHIN.</span>
@app.<span style="color: black;">register</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'demo.uuid'</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> get_uuid<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
   <span style="color: #808080; font-style: italic;"># Retourne un UUID, sans les tirets.</span>
   <span style="color: #808080; font-style: italic;"># ex: b27f7e9360c04efabfae5ac21a8f4e3c</span>
   <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">str</span><span style="color: black;">&#40;</span>uuid.<span style="color: black;">uuid4</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>.<span style="color: black;">replace</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'-'</span>, <span style="color: #483d8b;">''</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># On lance l'application. Ceci va lancer le serveur</span>
<span style="color: #808080; font-style: italic;"># puis le client. On peut désactiver le lancement du</span>
<span style="color: #808080; font-style: italic;"># serveur une fois qu'on met tout ça en prod.</span>
<span style="color: #ff7700;font-weight:bold;">if</span> __name__ == <span style="color: #483d8b;">'__main__'</span>:
    app.<span style="color: black;">run</span><span style="color: black;">&#40;</span>url=<span style="color: #483d8b;">&quot;ws://0.0.0.0:8080/&quot;</span><span style="color: black;">&#41;</span>
<span style="color: #808080; font-style: italic;"># On ne peut rien mettre comme code ici, il faut le</span>
<span style="color: #808080; font-style: italic;"># mettre dans @app.signal('onjoined') si on veut</span>
<span style="color: #808080; font-style: italic;"># entrer du code après que l'app soit lancée.</span></pre></div></div>

<p>Et on lance notre app :</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">python app.py</pre></div></div>

<p>Nous avons maintenant deux serveurs qui tournent : un serveur HTTP qui écoute sur le port 8000, et un serveur WAMP qui écoute sur le port 8080. En prod, crossbar peut servir à la fois HTTP et WAMP, donc pas besoin de lancer deux outils.</p>
<h2>Le lecteur video</h2>
<p>Il nous faut maintenant définir le comportement de notre lecteur video via Javascript. Il s&#8217;agit essentiellement de se connecter au serveur WAMP, et d&#8217;échanger des messages via RPC ou PUB/SUB :</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">  <span style="color: #003366; font-weight: bold;">var</span> player <span style="color: #339933;">=</span> <span style="color: #009900;">&#123;</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
  <span style="color: #003366; font-weight: bold;">var</span> url<span style="color: #339933;">;</span>
  <span style="color: #006600; font-style: italic;">/* On va utiliser du pur JS histoire de pas mélanger
    des notions de jQuery dans le tas. Je ne vais
    PAS utiliser les best practices sinon vous allez
    être noyés dans des détails */</span>
&nbsp;
  <span style="color: #009966; font-style: italic;">/* Lancer le code une fois que la page est chargée */</span>
  window.<span style="color: #660066;">addEventListener</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;load&quot;</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
&nbsp;
    <span style="color: #006600; font-style: italic;">/* Connexion au serveur WAMP. J'utilise
       les valeurs par défaut du serveur de
       dev. On ouvre explicitement la connection
       à la fin du script. */</span>
    <span style="color: #003366; font-weight: bold;">var</span> connection <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">new</span> autobahn.<span style="color: #660066;">Connection</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#123;</span>
       url<span style="color: #339933;">:</span> <span style="color: #3366CC;">'ws://'</span> <span style="color: #339933;">+</span> window.<span style="color: #660066;">location</span>.<span style="color: #660066;">hostname</span> <span style="color: #339933;">+</span> <span style="color: #3366CC;">':8080/'</span><span style="color: #339933;">,</span>
       realm<span style="color: #339933;">:</span> <span style="color: #3366CC;">'realm1'</span>
    <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #006600; font-style: italic;">/* Lancer ce code une fois que la connexion
       est réussie. Notez que je ne gère pas
       les erreurs dans dans une APP JS, c'est
       un puits sans fond. */</span>
    connection.<span style="color: #660066;">onopen</span> <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">function</span> <span style="color: #009900;">&#40;</span>session<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
&nbsp;
      <span style="color: #009966; font-style: italic;">/* Appel de la fonction ip() sur le serveur */</span>
      session.<span style="color: #660066;">call</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'demo.ip'</span><span style="color: #009900;">&#41;</span>
&nbsp;
      <span style="color: #006600; font-style: italic;">/* Une fois qu'on a récupéré l'IP,
         on peut fabriquer l'URL de notre
         projet et on appelle la fonction
         get_uuid() du serveur */</span>
      .<span style="color: #660066;">then</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>ip<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
        url <span style="color: #339933;">=</span> <span style="color: #3366CC;">'http://'</span> <span style="color: #339933;">+</span> ip <span style="color: #339933;">+</span> <span style="color: #3366CC;">':8000'</span><span style="color: #339933;">;</span>
        <span style="color: #000066; font-weight: bold;">return</span> session.<span style="color: #660066;">call</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'demo.uuid'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span>
&nbsp;
      <span style="color: #006600; font-style: italic;">/* Une fois qu'on a l'UUID, on peut commencer
         à gérer la partie télécommande */</span>
      .<span style="color: #660066;">then</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>uuid<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
&nbsp;
        <span style="color: #006600; font-style: italic;">/* Création du QR code avec le lien pointant
           sur la bonne URL. On met l'ID dans le hash. */</span>
        <span style="color: #003366; font-weight: bold;">var</span> controlUrl <span style="color: #339933;">=</span> url <span style="color: #339933;">+</span> <span style="color: #3366CC;">'/control.html#'</span> <span style="color: #339933;">+</span> uuid<span style="color: #339933;">;</span>
        <span style="color: #003366; font-weight: bold;">var</span> codeDiv <span style="color: #339933;">=</span> document.<span style="color: #660066;">getElementById</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;qrcode&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #003366; font-weight: bold;">new</span> QRCode<span style="color: #009900;">&#40;</span>codeDiv<span style="color: #339933;">,</span> controlUrl<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #003366; font-weight: bold;">var</span> ctrllink <span style="color: #339933;">=</span> document.<span style="color: #660066;">getElementById</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;ctrllink&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        ctrllink.<span style="color: #660066;">href</span> <span style="color: #339933;">=</span> controlUrl<span style="color: #339933;">;</span>
&nbsp;
        <span style="color: #006600; font-style: italic;">/* Notre travail consiste essentiellement à
           manipuler cet élément */</span>
        <span style="color: #003366; font-weight: bold;">var</span> video <span style="color: #339933;">=</span> document.<span style="color: #660066;">getElementById</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;vid&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
        <span style="color: #006600; font-style: italic;">/* On attache déclare 4 fonctions comme étant
           appelable à distance. Ces fonctions sont
           appelables en utilisant le nom composé
           de notre ID et de l'action qu'on souhaite
           faire. Ex:
           'b27f7e9360c04efabfae5ac21a8f4e3c.play'
           pour appeler &quot;play&quot; sur notre session. */</span>
        session.<span style="color: #660066;">register</span><span style="color: #009900;">&#40;</span>uuid <span style="color: #339933;">+</span> <span style="color: #3366CC;">'.play'</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
           video.<span style="color: #660066;">play</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
        session.<span style="color: #660066;">register</span><span style="color: #009900;">&#40;</span>uuid <span style="color: #339933;">+</span> <span style="color: #3366CC;">'.pause'</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
           video.<span style="color: #660066;">pause</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
        session.<span style="color: #660066;">register</span><span style="color: #009900;">&#40;</span>uuid <span style="color: #339933;">+</span> <span style="color: #3366CC;">'.volume'</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>val<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
           video.<span style="color: #660066;">volume</span> <span style="color: #339933;">=</span> val<span style="color: #009900;">&#91;</span><span style="color: #CC0000;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
        session.<span style="color: #660066;">register</span><span style="color: #009900;">&#40;</span>uuid <span style="color: #339933;">+</span> <span style="color: #3366CC;">'.status'</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>val<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
          <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #009900;">&#123;</span>
            <span style="color: #3366CC;">'playing'</span><span style="color: #339933;">:</span> <span style="color: #339933;">!</span>video.<span style="color: #660066;">paused</span><span style="color: #339933;">,</span>
            <span style="color: #3366CC;">'volume'</span><span style="color: #339933;">:</span> video.<span style="color: #660066;">volume</span>
          <span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
&nbsp;
&nbsp;
       <span style="color: #006600; font-style: italic;">/* Quelqu'un peut très bien
           appuyer sur play directement sur cette page.
&nbsp;
          Il faut donc réagir si l'utilisateur le fait,
          publier un événement via WAMP pour permettre
          à notre télécommande de se mettre à jour
          */</span>
       video.<span style="color: #660066;">addEventListener</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'play'</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
         <span style="color: #006600; font-style: italic;">/* On publie un message indiquant que
            le player a recommencé à lire la vidéo.
            */</span>
         session.<span style="color: #660066;">publish</span><span style="color: #009900;">&#40;</span>uuid <span style="color: #339933;">+</span> <span style="color: #3366CC;">'.play'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
       <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
        video.<span style="color: #660066;">addEventListener</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'pause'</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
          session.<span style="color: #660066;">publish</span><span style="color: #009900;">&#40;</span>uuid <span style="color: #339933;">+</span> <span style="color: #3366CC;">'.pause'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
        video.<span style="color: #660066;">addEventListener</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'volumechange'</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
          session.<span style="color: #660066;">publish</span><span style="color: #009900;">&#40;</span>uuid <span style="color: #339933;">+</span> <span style="color: #3366CC;">'.volume'</span><span style="color: #339933;">,</span> <span style="color: #009900;">&#91;</span>video.<span style="color: #660066;">volume</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
     <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #006600; font-style: italic;">/* Ouverture de la connection une fois que tous les
       callbacks sont bien en place.*/</span>
    connection.<span style="color: #000066;">open</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<h2>Code de la télécommande</h2>
<p>La télécommande est notre 3eme client WAMP (on peut avoir des centaines de clients WAMP). Notre 1er est l&#8217;App Python, notre second est le player.</p>
<p>Son code a pour but d&#8217;envoyer des ordres au player HTML5, mais aussi de mettre à jour son UI si le player change d&#8217;état.</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #006600; font-style: italic;">/* L'objet qui se charge de la logique de nos
   controles play/pause et changement de
   volume.
   Rien de fou, il change l'affichage
   du bouton et du slider selon qu'on
   est en pause/play et la valeur du
   volume.
   */</span>
<span style="color: #003366; font-weight: bold;">var</span> control <span style="color: #339933;">=</span> <span style="color: #009900;">&#123;</span>
   playing<span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">false</span><span style="color: #339933;">,</span>
   setPlaying<span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>val<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
      control.<span style="color: #660066;">playing</span> <span style="color: #339933;">=</span> val<span style="color: #339933;">;</span>
      <span style="color: #003366; font-weight: bold;">var</span> button <span style="color: #339933;">=</span> window.<span style="color: #660066;">document</span>.<span style="color: #660066;">getElementById</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'play'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>val<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
         button.<span style="color: #660066;">innerHTML</span> <span style="color: #339933;">=</span> <span style="color: #3366CC;">'Play'</span>
      <span style="color: #009900;">&#125;</span> <span style="color: #000066; font-weight: bold;">else</span> <span style="color: #009900;">&#123;</span>
         button.<span style="color: #660066;">innerHTML</span> <span style="color: #339933;">=</span> <span style="color: #3366CC;">'Pause'</span><span style="color: #339933;">;</span>
      <span style="color: #009900;">&#125;</span>
   <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span>
   setVolume<span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>val<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
      <span style="color: #003366; font-weight: bold;">var</span> slider <span style="color: #339933;">=</span> window.<span style="color: #660066;">document</span>.<span style="color: #660066;">getElementById</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'volume'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      slider.<span style="color: #660066;">value</span> <span style="color: #339933;">=</span> val<span style="color: #339933;">;</span>
   <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
window.<span style="color: #000066;">onload</span> <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
  <span style="color: #003366; font-weight: bold;">var</span> connection <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">new</span> autobahn.<span style="color: #660066;">Connection</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#123;</span>
    url<span style="color: #339933;">:</span> <span style="color: #3366CC;">'ws://'</span> <span style="color: #339933;">+</span> window.<span style="color: #660066;">location</span>.<span style="color: #660066;">hostname</span> <span style="color: #339933;">+</span> <span style="color: #3366CC;">':8080/'</span><span style="color: #339933;">,</span>
    realm<span style="color: #339933;">:</span> <span style="color: #3366CC;">'realm1'</span>
  <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
  connection.<span style="color: #660066;">onopen</span> <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">function</span> <span style="color: #009900;">&#40;</span>session<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
&nbsp;
    <span style="color: #009966; font-style: italic;">/* Récupération de l'ID dans le hash de l'URL */</span>
    <span style="color: #003366; font-weight: bold;">var</span> uuid <span style="color: #339933;">=</span> window.<span style="color: #660066;">location</span>.<span style="color: #660066;">hash</span>.<span style="color: #660066;">replace</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'#'</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">''</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #006600; font-style: italic;">/* Mise à jour des controles selon le status actuel
       du player grace à un appel RPC vers notre autre
       page. */</span>
    session.<span style="color: #660066;">call</span><span style="color: #009900;">&#40;</span>uuid <span style="color: #339933;">+</span> <span style="color: #3366CC;">'.status'</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">then</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #000066;">status</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
&nbsp;
      control.<span style="color: #660066;">setPlaying</span><span style="color: #009900;">&#40;</span><span style="color: #000066;">status</span><span style="color: #009900;">&#91;</span><span style="color: #3366CC;">'playing'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      control.<span style="color: #660066;">setVolume</span><span style="color: #009900;">&#40;</span><span style="color: #000066;">status</span><span style="color: #009900;">&#91;</span><span style="color: #3366CC;">'volume'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span>
&nbsp;
      <span style="color: #006600; font-style: italic;">/* On attache l'appui sur les contrôles à
         un appel de la fonction play() sur le
         player distant. L'uuid nous permet
         de n'envoyer l'événement que sur le
         bon player. */</span>
      control.<span style="color: #660066;">togglePlay</span> <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>control.<span style="color: #660066;">playing</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
          session.<span style="color: #660066;">call</span><span style="color: #009900;">&#40;</span>uuid <span style="color: #339933;">+</span> <span style="color: #3366CC;">'.pause'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
          control.<span style="color: #660066;">setPlaying</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">false</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span> <span style="color: #000066; font-weight: bold;">else</span> <span style="color: #009900;">&#123;</span>
          session.<span style="color: #660066;">call</span><span style="color: #009900;">&#40;</span>uuid <span style="color: #339933;">+</span> <span style="color: #3366CC;">'.play'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
          control.<span style="color: #660066;">setPlaying</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
      <span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
&nbsp;
      control.<span style="color: #660066;">volume</span> <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>val<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
        session.<span style="color: #660066;">call</span><span style="color: #009900;">&#40;</span>uuid <span style="color: #339933;">+</span> <span style="color: #3366CC;">'.volume'</span><span style="color: #339933;">,</span> <span style="color: #009900;">&#91;</span>val <span style="color: #339933;">/</span> <span style="color: #CC0000;">100</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      <span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
&nbsp;
      <span style="color: #006600; font-style: italic;">/* On ajoute un callback sur les événements
         de changement de status du player. Si
         quelqu'un fait play/pause ou change le
         volume, on veut mettre à jour la page. */</span>
      session.<span style="color: #660066;">subscribe</span><span style="color: #009900;">&#40;</span>uuid <span style="color: #339933;">+</span> <span style="color: #3366CC;">'.play'</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
        control.<span style="color: #660066;">setPlaying</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
      session.<span style="color: #660066;">subscribe</span><span style="color: #009900;">&#40;</span>uuid <span style="color: #339933;">+</span> <span style="color: #3366CC;">'.pause'</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
        control.<span style="color: #660066;">setPlaying</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">false</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
      session.<span style="color: #660066;">subscribe</span><span style="color: #009900;">&#40;</span>uuid <span style="color: #339933;">+</span> <span style="color: #3366CC;">'.volume'</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>val<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
        control.<span style="color: #660066;">setVolume</span><span style="color: #009900;">&#40;</span>val<span style="color: #009900;">&#91;</span><span style="color: #CC0000;">0</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">*</span> <span style="color: #CC0000;">100</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
&nbsp;
  connection.<span style="color: #000066;">open</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span></pre></div></div>

<h2>En résumé</h2>
<p>Voici à quoi ressemble le projet final :</p>
<pre>.
├── app.py (client python))
├── control.html (télécommande)
├── index.html (player video)
</pre>
<div id="attachment_11173" class="wp-caption aligncenter" style="width: 499px"><a href="media/e8d6da18.demo_video_wamp.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/06/demo_video_wamp.png"><img src="media/e8d6da18.demo_video_wamp.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/06/demo_video_wamp.png" alt="Schéma de fonctionnement de la démo" title="Bien que l&#039;app Python lance le serveur automatiquement et de manière invisible, c&#039;est bien un composant à part." width="489" height="346" class="size-full wp-image-11173" /></a><p class="wp-caption-text">Bien que l&#039;app Python lance le serveur automatiquement et de manière invisible, c&#039;est bien un composant à part.</p></div>
<p>Pour ce projet, on aura utilisé :</p>
<ul>
<li><a href="http://wamp.ws/">WAMP</a>: le protocole qui permet de faire communiquer en temps réel des parties d&#8217;application via RPC et PUB/SUB.</li>
<li><a href="http://autobahn.ws/js/">Autobahn.js</a>: une lib pour créer des clients WAMP en javascript.</li>
<li><a href="http://autobahn.ws/python/">Autobahn.py</a>: une lib pour créer des clients WAMP en Python.</li>
</ul>
<p>On n&#8217;aura pas utilisé crossbar, le serveur WAMP Python. On a utilisé un petit serveur de dev inclus dans autobahn. En prod, on utiliserait crossbar comme serveur WAMP.</p>
<p>Il y a pas mal de notions à prendre en compte.</p>
<p>D&#8217;abord, le <strong>RPC</strong>.</p>
<p>Cela permet à un client de dire &#8220;les autres clients peuvent appeler cette fonction à distance&#8221;. On l&#8217;utilise pour exposer <code>ip()</code> et <code>get_uuid()</code> sur notre serveur et notre javascript peut donc les appeler. Mais on l&#8217;utilise AUSSI pour qu&#8217;une des pages (le player) expose <code>play()</code>, <code>pause()</code> et <code>volume()</code> et que l&#8217;autre page (notre télécommande) puisse les utiliser.</p>
<p>La grosse différence, c&#8217;est que <code>ip()</code> peut être appelé par tous les clients en utilisant &#8220;demo.ip&#8221; alors que <code>play()</code> ne peut être appelé que par les clients qui connaissent l&#8217;ID du player, puisqu&#8217;il faut utiliser &#8220;&lt;id&gt;.play&#8221;.</p>
<p>Ensuite, il y a le <strong>PUB/SUB</strong>.</p>
<p>Cela permet à un client de dire &#8220;j&#8217;écoute tous les messages adressés à ce nom&#8221;. Et un autre client peut envoyer un message (on appelle ça aussi un événement, c&#8217;est pareil) sur ce nom, de telle sorte que tous les clients abonnés le reçoivent.</p>
<p>On l&#8217;utilise pour que notre télécommande dise &#8220;j&#8217;écoute tous les messages qui concernent les changements de status du player.&#8221; De l&#8217;autre côté, quand on clique sur un contrôle du player, on envoie un message précisant si le volume a changé, ou si on a appuyé sur play/pause. La télécommande peut ainsi mettre son UI à jour et refléter par exemple, la nouvelle valeur du volume.</p>
<p>Cela résume bien les usages principaux de ces deux outils :</p>
<ul>
<li>RPC permet de donner un ordre ou récupérer une information.</li>
<li>PUB/SUB permet de (se) tenir au courant d&#8217;un événement.</li>
</ul>
<p>Voici le workflow de notre projet :</p>
<ul>
<li>On lance un serveur WAMP.</li>
<li>On connecte des clients dessus (du code Python ou Js dans notre exemple).</li>
<li>Les clients déclarent les fonctions qu&#8217;ils exposent en RPC et les événements qu&#8217;ils écoutent en PUB/SUB.</li>
<li>Ensuite on réagit aux actions utilisateurs et on fait les appels RPC et les publications PUB/SUB en conséquence.</li>
</ul>
<p><strong>Si vous virez tous les commentaires, vous verrez que le code est en fait vraiment court pour une application aussi complexe.</strong></p>
<p>Encore une fois, il est possible de le faire sans WAMP, ce sera juste plus compliqué. Je vous invite à essayer de le faire pour vour rendre compte. Avec PHP, Ruby ou une app WSGI, c&#8217;est pas marrant du tout. Avec NodeJs, c&#8217;est plus simple, mais il faut quand même se taper la logique de gestion RPC et PUB/SUB à la main ou installer pas mal de libs en plus.</p>
<p>WAMP rend ce genre d&#8217;app triviale à écrire. Enfin triviale parce que là j&#8217;ignore tous les edge cases, évidemment. Pour un produit solide, il faut toujours suer un peu.</p>
<h2>Les limites du truc</h2>
<p>C&#8217;est du Python 2.7. Bientôt on pourra le faire avec asyncio et donc Python 3.4, mais malheureusement sans le serveur de dev.</p>
<p>Heureusement, Twisted est en cours de portage vers Python 3, et donc tout finira par marcher en 3.2+.</p>
<p>C&#8217;est du HTML5, mais bien entendu, rien ne vous empêche de faire ça avec du flash si ça vous amuse.</p>
<p>C&#8217;est du websocket, mais on peut utiliser un peu de flash pour <a href="https://github.com/gimite/web-socket-js">simuler websocket</a> pour les vieux navigateurs qui ne le supportent pas.</p>
<p>Non, la vraie limite c&#8217;est encore la jeunesse du projet : pas d&#8217;autoreload pour le serveur (super chiant de devoir le faire à la main à chaque fois qu&#8217;on modifie le code) et les erreurs côté serveur se lisent dans la console JS, et pas dans le terminal depuis lequel on a lancé le serveur. Plein de petits détails comme ça.</p>
<h2>EDIT: Mise en prod</h2>
<p>On m&#8217;a demandé à quoi ça ressemblerait si on mettais le truc en prod, alors je vais donner un exemple.</p>
<p>D&#8217;abord, on installe crossbar :</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">pip <span style="color: #c20cb9; font-weight: bold;">install</span> crossbar</pre></div></div>

<p>Ensuite, on le fait créer un dossier de configuration :</p>
<p><code>crossbar init</code></p>
<p>Ça va créer un dossier <code>.crossbar</code> avec un fichier <code>config.json</code> dedans.</p>
<p>On édite le fichier, de telle sorte qu&#8217;il ressemble à ça :</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #009900;">&#123;</span>
   <span style="color: #3366CC;">&quot;controller&quot;</span><span style="color: #339933;">:</span> <span style="color: #009900;">&#123;</span>
   <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span>
   <span style="color: #3366CC;">&quot;workers&quot;</span><span style="color: #339933;">:</span> <span style="color: #009900;">&#91;</span>
      <span style="color: #009900;">&#123;</span>
         <span style="color: #3366CC;">&quot;type&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;router&quot;</span><span style="color: #339933;">,</span>
         <span style="color: #3366CC;">&quot;options&quot;</span><span style="color: #339933;">:</span> <span style="color: #009900;">&#123;</span>
            <span style="color: #3366CC;">&quot;pythonpath&quot;</span><span style="color: #339933;">:</span> <span style="color: #009900;">&#91;</span><span style="color: #3366CC;">&quot;..&quot;</span><span style="color: #009900;">&#93;</span>
         <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span>
         <span style="color: #3366CC;">&quot;realms&quot;</span><span style="color: #339933;">:</span> <span style="color: #009900;">&#91;</span>
            <span style="color: #009900;">&#123;</span>
               <span style="color: #3366CC;">&quot;name&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;realm1&quot;</span><span style="color: #339933;">,</span>
               <span style="color: #3366CC;">&quot;roles&quot;</span><span style="color: #339933;">:</span> <span style="color: #009900;">&#91;</span>
                  <span style="color: #009900;">&#123;</span>
                     <span style="color: #3366CC;">&quot;name&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;anonymous&quot;</span><span style="color: #339933;">,</span>
                     <span style="color: #3366CC;">&quot;permissions&quot;</span><span style="color: #339933;">:</span> <span style="color: #009900;">&#91;</span>
                        <span style="color: #009900;">&#123;</span>
                           <span style="color: #3366CC;">&quot;uri&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;*&quot;</span><span style="color: #339933;">,</span>
                           <span style="color: #3366CC;">&quot;publish&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">true</span><span style="color: #339933;">,</span>
                           <span style="color: #3366CC;">&quot;subscribe&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">true</span><span style="color: #339933;">,</span>
                           <span style="color: #3366CC;">&quot;call&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">true</span><span style="color: #339933;">,</span>
                           <span style="color: #3366CC;">&quot;register&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">true</span>
                        <span style="color: #009900;">&#125;</span>
                     <span style="color: #009900;">&#93;</span>
                  <span style="color: #009900;">&#125;</span>
               <span style="color: #009900;">&#93;</span>
            <span style="color: #009900;">&#125;</span>
         <span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span>
         <span style="color: #3366CC;">&quot;transports&quot;</span><span style="color: #339933;">:</span> <span style="color: #009900;">&#91;</span>
            <span style="color: #009900;">&#123;</span>
               <span style="color: #3366CC;">&quot;type&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;web&quot;</span><span style="color: #339933;">,</span>
               <span style="color: #3366CC;">&quot;endpoint&quot;</span><span style="color: #339933;">:</span> <span style="color: #009900;">&#123;</span>
                  <span style="color: #3366CC;">&quot;type&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;tcp&quot;</span><span style="color: #339933;">,</span>
                  <span style="color: #3366CC;">&quot;port&quot;</span><span style="color: #339933;">:</span> <span style="color: #CC0000;">8080</span>
               <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span>
               <span style="color: #3366CC;">&quot;paths&quot;</span><span style="color: #339933;">:</span> <span style="color: #009900;">&#123;</span>
                  <span style="color: #3366CC;">&quot;/&quot;</span><span style="color: #339933;">:</span> <span style="color: #009900;">&#123;</span>
                     <span style="color: #3366CC;">&quot;type&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;static&quot;</span><span style="color: #339933;">,</span>
                     <span style="color: #3366CC;">&quot;directory&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;../templates&quot;</span>
                  <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span>
                  <span style="color: #3366CC;">&quot;ws&quot;</span><span style="color: #339933;">:</span> <span style="color: #009900;">&#123;</span>
                     <span style="color: #3366CC;">&quot;type&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;websocket&quot;</span>
                  <span style="color: #009900;">&#125;</span>
               <span style="color: #009900;">&#125;</span>
            <span style="color: #009900;">&#125;</span>
         <span style="color: #009900;">&#93;</span>
      <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span>
      <span style="color: #009900;">&#123;</span>
         <span style="color: #3366CC;">&quot;type&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;container&quot;</span><span style="color: #339933;">,</span>
         <span style="color: #3366CC;">&quot;options&quot;</span><span style="color: #339933;">:</span> <span style="color: #009900;">&#123;</span>
            <span style="color: #3366CC;">&quot;pythonpath&quot;</span><span style="color: #339933;">:</span> <span style="color: #009900;">&#91;</span><span style="color: #3366CC;">&quot;..&quot;</span><span style="color: #009900;">&#93;</span>
         <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span>
         <span style="color: #3366CC;">&quot;components&quot;</span><span style="color: #339933;">:</span> <span style="color: #009900;">&#91;</span>
            <span style="color: #009900;">&#123;</span>
               <span style="color: #3366CC;">&quot;type&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;class&quot;</span><span style="color: #339933;">,</span>
               <span style="color: #3366CC;">&quot;classname&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;app.app&quot;</span><span style="color: #339933;">,</span>
               <span style="color: #3366CC;">&quot;realm&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;realm1&quot;</span><span style="color: #339933;">,</span>
               <span style="color: #3366CC;">&quot;transport&quot;</span><span style="color: #339933;">:</span> <span style="color: #009900;">&#123;</span>
                  <span style="color: #3366CC;">&quot;type&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;websocket&quot;</span><span style="color: #339933;">,</span>
                  <span style="color: #3366CC;">&quot;endpoint&quot;</span><span style="color: #339933;">:</span> <span style="color: #009900;">&#123;</span>
                     <span style="color: #3366CC;">&quot;type&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;tcp&quot;</span><span style="color: #339933;">,</span>
                     <span style="color: #3366CC;">&quot;host&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;127.0.0.1&quot;</span><span style="color: #339933;">,</span>
                     <span style="color: #3366CC;">&quot;port&quot;</span><span style="color: #339933;">:</span> <span style="color: #CC0000;">8080</span>
                  <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span>
                  <span style="color: #3366CC;">&quot;url&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;ws://127.0.0.1/ws&quot;</span>
               <span style="color: #009900;">&#125;</span>
            <span style="color: #009900;">&#125;</span>
         <span style="color: #009900;">&#93;</span>
      <span style="color: #009900;">&#125;</span>
   <span style="color: #009900;">&#93;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Ceci n&#8217;est pas un tuto sur la mise en prod d&#8217;un projet WAMP avec crossbar, alors je ne vais pas rentrer dans les détails, mais en gros on change les ports HTTP et WAMP pour le port 8080, et on donne juste l&#8217;url <code>/ws</code> comme point d&#8217;entrée pour WAMP (on doit éditer le code source de la démo en conséquence). On sert les fichiers statiques en utilisant la section &#8220;transports&#8221; et notre app via la section &#8220;components&#8221;. Pour le realm, encore une fois, je skip, c&#8217;est un sujet à part, celui par défaut marche pour notre usage.</p>
<p>A partir de là il y a plusieurs solutions possibles :</p>
<ul>
<li>On souhaite que crossbar gère tout lui-même. Dans ce cas il faut utiliser <a href="https://wiki.apache.org/httpd/NonRootPortBinding">un outil</a> pour binder le port 80 sur le port 8080. Ça évite de lancer crossbar en root.</li>
<li>On peut mettre nginx devant (parce qu&#8217;on en a déjà un qui tourne, parce que c&#8217;est cool pour le load balancing, parce l&#8217;hébergeur le fournit) et dans ce cas, comme pour les autres config, il faut qu&#8217;il fasse un <a href="">proxy_pass</a> pour HTTP et Websocket sur les bonnes URLs.</li>
<li>On est un gros bourrin, on met le port 80 dans le fichier de config, on lance le tout avec un sudo et on sert les fesses. Si un sys admin passe par là il vous lapidera, mais ça marche bien et facilement tant que personne n&#8217;essaye de pirater votre serveur :)</li>
</ul>
<p>Pour lancer la machine :</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">crossbar run</pre></div></div>

<p>On met un petit script d&#8217;init pour le lancer au démarrage, et on est good.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=11146&amp;md5=229ce90a2b3a4686669eef89a213ec29" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=11199
title: La fin de l’ère du spam de sites pornos
uri: La-fin-de-l-ère-du-spam-de-sites-pornos
url: http://sametmax.com/la-fin-de-lere-du-spam-de-sites-pornos/
content:
<p>Petit billet juste pour dire que cette époque où tout mail entré dans un formulaire sur un site de cul se retrouvait immédiatement noyé dans un flot d&#8217;emails publicitaires touche à sa fin.</p>
<p>L&#8217;industrie adulte a-t-elle soudainement une crise morale ?</p>
<p>Non, c&#8217;est juste que ce n&#8217;est plus efficace du tout.</p>
<p>La plupart des mails sont maintenant arrêtés sans efforts de l’utilisateur par tous les grands services de mails gratuits. Ils ne les voient même pas. En fait, ça en devient chiant car parfois les mails de confirmation d&#8217;ouverture de compte, les liens de validation et les reset de mots de passe y tombent aussi si le nom de domaine est trop tendancieux.</p>
<p>Le mail, en soit, n&#8217;a pas disparu. La mailling list est toujours d&#8217;actu, et fonctionne bien : le user peut se désabonner pour de vrai, et les intéressés (il y en a plus que le geek en moi veut l&#8217;admettre) cliquent consciemment sur les liens qu&#8217;elle inclus.</p>
<p>Le spam n&#8217;a pas disparu non plus. Il a changé de forme. On ne vend plus les mêmes choses, de la même façon. Mais les spams de cul sont une espèce en voie de disparition. Les derniers à le faire ont sans doute juste oublié de killer leur CRON.</p>
<p>RIP</p>
<p>J&#8217;ai commencé ma carrière dans un boîte qui faisait du spam SMS. Et ça malheureusement, ça ne se désengorge pas, j&#8217;en reçois toujours aujourd&#8217;hui. Le karma je vous dis, le karma&#8230;</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=11199&amp;md5=07a863b91169b1ab18bb1c071b27bd36" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=11208
title: Annuler les derniers commits avec Git
uri: Inverser-les-derniers-commits-avec-Git
url: http://sametmax.com/inverser-les-derniers-commits-avec-git/
content:
<p><em>(Amélioration de ce dont je parle <a href="http://sametmax.com/git-revert-pour-annuler-proprement-le-dernier-commit/">ici</a>)</em></p>
<p>Use case typique : on a merdé les derniers commits, et on veut oublier tout ce qu&#8217;on a fait et retourner à l&#8217;état d&#8217;il y a x commits précédents.</p>
<p>Par exemple, là je veux revenir à mon commit <code>85711ad...</code> :</p>
<pre>commit 093bab5aa9d41f580037d51421b7c5d0db73e2ce
Author: sam <lesametlemax@gmail.com>
Date:   Sat Jun 28 09:37:55 2014 +0700

    Ok, c'est la merde internationale

commit 0b768f1c0e37a6141e6cd4c472eb3f369f4334d7
Author: sam <lesametlemax@gmail.com>
Date:   Sat Jun 28 09:37:36 2014 +0700

    Je commence à merder

commit 85711ad1e8c54f3fd3048d405addef48921e90fd
Author: sam <lesametlemax@gmail.com>
Date:   Sat Jun 28 09:37:20 2014 +0700

    J'adore ce commit</pre>
<p>Il y a plein de manières de faire, et on voit sur la toile beaucoup de solutions à base de <code>checkout</code> et de <code>reset</code>. La plupart sont dangereuses ou ont un résultat inattendu, présuppose un état de votre repo ou va vous mettre dans une situation que vous ne maîtrisez pas.</p>
<p>Devinez quoi ? Il y a plus simple, et plus propre.</p>
<h2>Etape 1: avoir une copie de travail propre</h2>
<p>Avant d&#8217;inverser des commits, assurez vous que votre copie de travail est nette. Pas de fichiers modifiés en attente d&#8217;être commités. Le moins de fichiers non trackés par git possible (idéalement zéro, soit c&#8217;est commité, soit c&#8217;est dans le .gitignore).</p>
<p>Si vous avez des fichiers modifiés, vous pouvez soit les mettre de côté temporairement avec <a href="http://sametmax.com/soyez-relax-faites-vous-un-petit-git-stash/">git stash</a>, soit annuler toutes les modifications avec <code>git reset --hard HEAD</code>. Attention, cette dernière commande n&#8217;est pas réversible et va mettre à plat votre copie de travail pour qu&#8217;elle soit l&#8217;exacte copie du dernier commit de votre histo.</p>
<h2>Etape 2</h2>
<p>???</p>
<h2>Etape 3: profit !</h2>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">git</span> revert <span style="color: #660033;">--no-commit</span> 85711ad1..HEAD</pre></div></div>

<p>Ceci va modifier la copie de travail (donc les fichiers que vous avez sur le disque dur en direct, pas l&#8217;histo git) en appliquant des patchs qui contiennent les différences entre HEAD et le commit avec ce hash.</p>
<p>En clair : vos fichiers vont être dans l&#8217;état dans lequel ils étaient à ce commit. En prime, l&#8217;index est mis à jour.</p>
<p>Vous pouvez alors faire les derniers ajustements que vous le souhaitez. Il faut ensuite finaliser la procédure par un commit avec un message significatif :</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">git</span> commit <span style="color: #660033;">-m</span> <span style="color: #ff0000;">&quot;Abort ! Abort ! Inversion des 2 derniers commits, retour à 85711a&quot;</span></pre></div></div>

<p>Si vous aviez fait un <code>stash</code>, c&#8217;est le moment de faire un <code>stash apply</code> derrière.</p>
<p>Maintenant, si vous matez l&#8217;histo, vous verrez qu&#8217;on n&#8217;a pas effacé les commits précédents, on a juste fait un commit qui inverse tout ce qu&#8217;ils avaient fait :</p>
<pre>
commit 03e55de36ad29a26a461874988d4066ebf6fe6be
Author: sam <lesametlemax@gmail.com>
Date:   Sat Jun 28 09:43:32 2014 +0700

    Abort ! Abort ! Inversion des 2 derniers commits, retour à 85711a

commit 093bab5aa9d41f580037d51421b7c5d0db73e2ce
Author: sam <lesametlemax@gmail.com>
Date:   Sat Jun 28 09:37:55 2014 +0700

    Ok, c'est la merde internationale

commit 0b768f1c0e37a6141e6cd4c472eb3f369f4334d7
Author: sam <lesametlemax@gmail.com>
Date:   Sat Jun 28 09:37:36 2014 +0700

    Je commence à merder

commit 85711ad1e8c54f3fd3048d405addef48921e90fd
Author: sam <lesametlemax@gmail.com>
Date:   Sat Jun 28 09:37:20 2014 +0700

    J'adore ce commit
</pre>
<p>Ce qui évite bien des problèmes : pas de réécriture de l&#8217;histo, possibilité de récupérer du code dans les commits inversés plus tard, claire indication de ce qui s&#8217;est passé&#8230;</p>
<p>N&#8217;oubliez pas que souvent, revenir à un commit précédent est overkill. Il est généralement beaucoup plus simple de juste récupérer un ou deux fichiers dans l&#8217;état de l&#8217;époque avec :</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">git</span> checkout <span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #7a0874; font-weight: bold;">hash</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> <span style="color: #660033;">--</span> chemin<span style="color: #000000; font-weight: bold;">/</span>vers<span style="color: #000000; font-weight: bold;">/</span>fichier</pre></div></div>

 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=11208&amp;md5=da4fb50d7c3b709f9afe9ce85d831d2f" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=11217
title: Aller plus loin avec les hash maps en Python
uri: Aller-plus-loin-avec-les-hash-maps-en-Python
url: http://sametmax.com/aller-plus-loin-avec-les-hash-maps-en-python/
content:
<p>Les hash map sont souvent sous-utilisés, surtout par les personnes venant d&#8217;un autre langage avec implémentation vraiment batarde du concept. Les arrays en PHP et les objets en Javascript étant parmi les pires exemples.</p>
<p>Le point d&#8217;entrée pour les hash maps en Python, c&#8217;est le dictionnaire. Et la plupart des gens ont pigé le principe de l&#8217;association clé / valeur :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> d = <span style="color: black;">&#123;</span><span style="color: black;">&#125;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> d<span style="color: black;">&#91;</span><span style="color: #483d8b;">'cle'</span><span style="color: black;">&#93;</span> = <span style="color: #483d8b;">'valeur'</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> d<span style="color: black;">&#91;</span><span style="color: #483d8b;">'cle'</span><span style="color: black;">&#93;</span>
<span style="color: #483d8b;">'valeur'</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> d<span style="color: black;">&#91;</span><span style="color: #483d8b;">'pas cle'</span><span style="color: black;">&#93;</span>
Traceback <span style="color: black;">&#40;</span>most recent call last<span style="color: black;">&#41;</span>:
  File <span style="color: #483d8b;">&quot;&lt;ipython-input-12-eed7cf6f5344&gt;&quot;</span>, line <span style="color: #ff4500;">1</span>, <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #66cc66;">&lt;</span>module<span style="color: #66cc66;">&gt;</span>
    d<span style="color: black;">&#91;</span><span style="color: #483d8b;">'pas cle'</span><span style="color: black;">&#93;</span>
<span style="color: #008000;">KeyError</span>: <span style="color: #483d8b;">'pas cle'</span></pre></div></div>

<p>L’intérêt du dictionnaire étant qu&#8217;accéder à une clé est très rapide (c&#8217;est <a href="http://sametmax.com/complexite-algorithmique-pourquoi-tant-de-n/">une opération O(1)</a>), tout comme vérifier qu&#8217;une clé est présente dans le dico :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #483d8b;">'cle'</span> <span style="color: #ff7700;font-weight:bold;">in</span> d
<span style="color: #008000;">True</span></pre></div></div>

<p>Mais généralement les gens s&#8217;arrêtent là.</p>
<h2>Itération</h2>
<p>Parfois, ils vont plus loin, et tentent l&#8217;itération dessus :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> scores = <span style="color: black;">&#123;</span><span style="color: #483d8b;">&quot;Joe&quot;</span>: <span style="color: #ff4500;">1</span>, <span style="color: #483d8b;">&quot;Jonh&quot;</span>: <span style="color: #ff4500;">5</span>, <span style="color: #483d8b;">&quot;Jack&quot;</span>: <span style="color: #ff4500;">3</span>, <span style="color: #483d8b;">&quot;Jenny&quot;</span>: <span style="color: #ff4500;">7</span>, <span style="color: #483d8b;">&quot;Jeanne&quot;</span>: <span style="color: #ff4500;">0</span>, <span style="color: #483d8b;">&quot;July&quot;</span>: <span style="color: #ff4500;">3</span><span style="color: black;">&#125;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">for</span> score <span style="color: #ff7700;font-weight:bold;">in</span> scores:
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>score<span style="color: black;">&#41;</span>
...
<span style="color: black;">Jenny</span>
Jack
Joe
July
Jonh
Jeanne</pre></div></div>

<p>Ils s’aperçoivent qu&#8217;on peut uniquement récupérer les clés, et essayent de faire ça :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">for</span> nom <span style="color: #ff7700;font-weight:bold;">in</span> scores:
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>nom, scores<span style="color: black;">&#91;</span>nom<span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
...
<span style="color: black;">Jenny</span> <span style="color: #ff4500;">7</span>
Jack <span style="color: #ff4500;">3</span>
Joe <span style="color: #ff4500;">1</span>
July <span style="color: #ff4500;">3</span>
Jonh <span style="color: #ff4500;">5</span>
Jeanne <span style="color: #ff4500;">0</span></pre></div></div>

<p>Rapidement ils sont corrigés par quelques collègues qui leur expliquent qu&#8217;on peut faire ceci :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">for</span> nom, score <span style="color: #ff7700;font-weight:bold;">in</span> scores.<span style="color: black;">items</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>nom, score<span style="color: black;">&#41;</span>
...
<span style="color: black;">Jenny</span> <span style="color: #ff4500;">7</span>
Jack <span style="color: #ff4500;">3</span>
Joe <span style="color: #ff4500;">1</span>
July <span style="color: #ff4500;">3</span>
Jonh <span style="color: #ff4500;">5</span>
Jeanne <span style="color: #ff4500;">0</span></pre></div></div>

<p>Sans vraiment expliquer pourquoi. Si vous êtes curieux, cela marche grâce à l&#8217;<a href="http://sametmax.com/tag/unpacking/">unpacking</a>.</p>
<p>Ensuite ils vont chercher à afficher des choses dans l&#8217;ordre, mais un dictionnaire n&#8217;est pas ordonné. Là commencent les embrouilles : dans l&#8217;ordre des clés, des valeurs ou dans l&#8217;ordre d&#8217;insertion ?</p>
<p>Dans l&#8217;ordre des clés ou des valeurs, il faut se taper le <a href="http://sametmax.com/ordonner-en-python/">tri</a> à chaque fois :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">for</span> nom, score <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">sorted</span><span style="color: black;">&#40;</span>scores.<span style="color: black;">items</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>nom, score<span style="color: black;">&#41;</span>
...
<span style="color: black;">Jack</span> <span style="color: #ff4500;">3</span>
Jeanne <span style="color: #ff4500;">0</span>
Jenny <span style="color: #ff4500;">7</span>
Joe <span style="color: #ff4500;">1</span>
Jonh <span style="color: #ff4500;">5</span>
July <span style="color: #ff4500;">3</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">for</span> nom, score <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">sorted</span><span style="color: black;">&#40;</span>scores.<span style="color: black;">items</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>, key=<span style="color: #ff7700;font-weight:bold;">lambda</span> x: x<span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>nom, score<span style="color: black;">&#41;</span>
...
<span style="color: black;">Jeanne</span> <span style="color: #ff4500;">0</span>
Joe <span style="color: #ff4500;">1</span>
Jack <span style="color: #ff4500;">3</span>
July <span style="color: #ff4500;">3</span>
Jonh <span style="color: #ff4500;">5</span>
Jenny <span style="color: #ff4500;">7</span></pre></div></div>

<p>Dans l&#8217;ordre d&#8217;insertion par contre, ce n&#8217;est pas possible avec le dictionnaire. Mais voilà l&#8217;astuce : le hash map en Python, ce n&#8217;est pas QUE le type <code>dict</code>.</p>
<p>Pour ce problème, on peut utiliser <code>collections.OrderedDict</code> :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">from</span> <span style="color: #dc143c;">collections</span> <span style="color: #ff7700;font-weight:bold;">import</span> OrderedDict
<span style="color: #66cc66;">&gt;&gt;&gt;</span> d = OrderedDict<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> d<span style="color: black;">&#91;</span><span style="color: #483d8b;">'Jeanne'</span><span style="color: black;">&#93;</span> = <span style="color: #ff4500;">3</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> d<span style="color: black;">&#91;</span><span style="color: #483d8b;">'Jack'</span><span style="color: black;">&#93;</span> = <span style="color: #ff4500;">2</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> d<span style="color: black;">&#91;</span><span style="color: #483d8b;">'July'</span><span style="color: black;">&#93;</span> = <span style="color: #ff4500;">6</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">for</span> nom, score <span style="color: #ff7700;font-weight:bold;">in</span> d.<span style="color: black;">items</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>nom, score<span style="color: black;">&#41;</span>
...
<span style="color: black;">Jeanne</span> <span style="color: #ff4500;">3</span>
Jack <span style="color: #ff4500;">2</span>
July <span style="color: #ff4500;">6</span></pre></div></div>

<p>Après il y a le rare problème, mais tout de même existant, de la très très grosse structure de données que l&#8217;on veut itérer dans l&#8217;ordre de clés :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">random</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> l = <span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">10000000</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #dc143c;">random</span>.<span style="color: black;">shuffle</span><span style="color: black;">&#40;</span>l<span style="color: black;">&#41;</span></pre></div></div>

<p>Si on fait un sort dessus, ça prend plusieurs secondes :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> l.<span style="color: black;">sort</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Imaginez avec un dico qui contient un million de clés sous forme de texte. La lecture dans l&#8217;ordre sera très, très lente. Parfois ce n&#8217;est pas grave, et parfois c&#8217;est très emmerdant.</p>
<p>La stdlib de Python ne permet pas de répondre à ce problème facilement. On pourrait bricoler quelque chose avec <a href="http://sametmax.com/heapq-le-module-python-incompris/">heapq</a>, mais franchement, c&#8217;est se casser la tête pour rien.</p>
<p>Le plus simple est d&#8217;utiliser une lib externe, par exemple l&#8217;excellente <a href="https://github.com/grantjenks/sorted_containers">sorted_container</a>, qui en plus d&#8217;être très rapide, est en pur Python. Du coup, un peu de <a href="http://sametmax.com/votre-python-aime-les-pip/">pip</a> :</p>
<p><code>pip install sorted_container</code></p>
<p>Et on est bon.</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">from</span> sortedcontainers <span style="color: #ff7700;font-weight:bold;">import</span> SortedDict
<span style="color: #66cc66;">&gt;&gt;&gt;</span> d = SortedDict<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> d<span style="color: black;">&#91;</span><span style="color: #483d8b;">'Joe'</span><span style="color: black;">&#93;</span> = <span style="color: #ff4500;">1</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> d<span style="color: black;">&#91;</span><span style="color: #483d8b;">'Jeanne'</span><span style="color: black;">&#93;</span> = <span style="color: #ff4500;">6</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> d<span style="color: black;">&#91;</span><span style="color: #483d8b;">'July'</span><span style="color: black;">&#93;</span> = <span style="color: #ff4500;">3</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> d<span style="color: black;">&#91;</span><span style="color: #483d8b;">'John'</span><span style="color: black;">&#93;</span> = <span style="color: #ff4500;">3</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">for</span> nom, score <span style="color: #ff7700;font-weight:bold;">in</span> d.<span style="color: black;">items</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>nom, score<span style="color: black;">&#41;</span>
...
<span style="color: black;">Jeanne</span> <span style="color: #ff4500;">6</span>
Joe <span style="color: #ff4500;">1</span>
John <span style="color: #ff4500;">3</span>
July <span style="color: #ff4500;">3</span></pre></div></div>

<p>SortedDict s&#8217;assure que le dictionnaire reste ordonné à chaque insertion d&#8217;un élément, et ainsi, vous évite de devoir faire un tri tout à la fin.</p>
<h2>Initialisation</h2>
<p>La plupart du temps, on utilise la notation littérale. Mais le constructeur <code>dict</code> trouve son utilité dans le fait qu&#8217;il accepte un itérable de tuples en paramètre :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #008000;">dict</span><span style="color: black;">&#40;</span><span style="color: black;">&#91;</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;a&quot;</span>, <span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>, <span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;b&quot;</span>, <span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
<span style="color: black;">&#123;</span><span style="color: #483d8b;">'a'</span>: <span style="color: #ff4500;">1</span>, <span style="color: #483d8b;">'b'</span>: <span style="color: #ff4500;">2</span><span style="color: black;">&#125;</span></pre></div></div>

<p>La plupart du temps, les gens n&#8217;en voient pas l&#8217;utilité. Mais il faut se rappeler que tout le langage Python est organisé autour de l&#8217;itération. Je ne cesse de le répéter, en Python, l&#8217;itération est tout.</p>
<p>De fait, cette particularité du constructeur du dico vous permet de créer des dictionnaires à partir de structures existantes inattendues&#8230;</p>
<p>Prendre deux séquences et les pairer :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> personnes = <span style="color: black;">&#40;</span><span style="color: #483d8b;">'Joe'</span>, <span style="color: #483d8b;">'John'</span>, <span style="color: #483d8b;">'Jean-Michel'</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> scores = <span style="color: black;">&#40;</span><span style="color: #ff4500;">4</span>, <span style="color: #ff4500;">10</span>, <span style="color: #ff4500;">34</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #008000;">zip</span><span style="color: black;">&#40;</span>personnes, scores<span style="color: black;">&#41;</span>
<span style="color: black;">&#91;</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Joe'</span>, <span style="color: #ff4500;">4</span><span style="color: black;">&#41;</span>, <span style="color: black;">&#40;</span><span style="color: #483d8b;">'John'</span>, <span style="color: #ff4500;">10</span><span style="color: black;">&#41;</span>, <span style="color: black;">&#40;</span><span style="color: #483d8b;">'Jean-michel'</span>, <span style="color: #ff4500;">34</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #008000;">dict</span><span style="color: black;">&#40;</span><span style="color: #008000;">zip</span><span style="color: black;">&#40;</span>personnes, scores<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: black;">&#123;</span><span style="color: #483d8b;">'Jean-michel'</span>: <span style="color: #ff4500;">34</span>, <span style="color: #483d8b;">'John'</span>: <span style="color: #ff4500;">10</span>, <span style="color: #483d8b;">'Joe'</span>: <span style="color: #ff4500;">4</span><span style="color: black;">&#125;</span></pre></div></div>

<p>Pairer les deux derniers champs du résultat d&#8217;une commande :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">subprocess</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> df = <span style="color: #dc143c;">subprocess</span>.<span style="color: black;">check_output</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'df'</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>df<span style="color: black;">&#41;</span>
Sys. <span style="color: black;">de</span> fichiers       blocks de 1K  Utilisé Disponible Uti<span style="color: #66cc66;">%</span> Monté sur
/dev/sda7                   <span style="color: #ff4500;">7972000</span>  <span style="color: #ff4500;">6614840</span>     <span style="color: #ff4500;">929156</span>  <span style="color: #ff4500;">88</span><span style="color: #66cc66;">%</span> /
none                              <span style="color: #ff4500;">4</span>        <span style="color: #ff4500;">0</span>          <span style="color: #ff4500;">4</span>   <span style="color: #ff4500;">0</span><span style="color: #66cc66;">%</span> /<span style="color: #dc143c;">sys</span>/fs/cgroup
udev                        <span style="color: #ff4500;">1968688</span>        <span style="color: #ff4500;">4</span>    <span style="color: #ff4500;">1968684</span>   <span style="color: #ff4500;">1</span><span style="color: #66cc66;">%</span> /dev
tmpfs                        <span style="color: #ff4500;">395896</span>     <span style="color: #ff4500;">1112</span>     <span style="color: #ff4500;">394784</span>   <span style="color: #ff4500;">1</span><span style="color: #66cc66;">%</span> /run
none                           <span style="color: #ff4500;">5120</span>        <span style="color: #ff4500;">0</span>       <span style="color: #ff4500;">5120</span>   <span style="color: #ff4500;">0</span><span style="color: #66cc66;">%</span> /run/lock
none                        <span style="color: #ff4500;">1979472</span>      <span style="color: #ff4500;">160</span>    <span style="color: #ff4500;">1979312</span>   <span style="color: #ff4500;">1</span><span style="color: #66cc66;">%</span> /run/shm
none                         <span style="color: #ff4500;">102400</span>       <span style="color: #ff4500;">44</span>     <span style="color: #ff4500;">102356</span>   <span style="color: #ff4500;">1</span><span style="color: #66cc66;">%</span> /run/<span style="color: #dc143c;">user</span>
/dev/sda5                  <span style="color: #ff4500;">65438480</span> <span style="color: #ff4500;">57693436</span>    <span style="color: #ff4500;">4397852</span>  <span style="color: #ff4500;">93</span><span style="color: #66cc66;">%</span> /media/sam/
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #008000;">dict</span><span style="color: black;">&#40;</span>l.<span style="color: black;">split</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#91;</span>-<span style="color: #ff4500;">2</span>:<span style="color: black;">&#93;</span> <span style="color: #ff7700;font-weight:bold;">for</span> l <span style="color: #ff7700;font-weight:bold;">in</span>  <span style="color: #008000;">list</span><span style="color: black;">&#40;</span>df.<span style="color: black;">split</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'<span style="color: #000099; font-weight: bold;">\n</span>'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span>:<span style="color: black;">&#93;</span> <span style="color: #ff7700;font-weight:bold;">if</span> l<span style="color: black;">&#41;</span>
<span style="color: black;">&#123;</span><span style="color: #483d8b;">'31%'</span>: <span style="color: #483d8b;">'/media/truecrypt1'</span>, <span style="color: #483d8b;">'1%'</span>: <span style="color: #483d8b;">'/run/user'</span>, <span style="color: #483d8b;">'93%'</span>: <span style="color: #483d8b;">'/media/sam'</span>, <span style="color: #483d8b;">'88%'</span>: <span style="color: #483d8b;">'/'</span>, <span style="color: #483d8b;">'0%'</span>: <span style="color: #483d8b;">'/run/lock'</span><span style="color: black;">&#125;</span></pre></div></div>

<p>Depuis Python 2.7, cette fonctionnalité est partiellement phagocytée par la syntaxe pour <a href="http://sametmax.com/python-love-les-listes-en-intention-partie/">les intentions</a> sur les dicos :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">from</span> <span style="color: #dc143c;">pprint</span> <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">pprint</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #dc143c;">pprint</span><span style="color: black;">&#40;</span> <span style="color: black;">&#123;</span>line: num <span style="color: #ff7700;font-weight:bold;">for</span> num, line <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">enumerate</span><span style="color: black;">&#40;</span><span style="color: #008000;">open</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'/etc/fstab'</span><span style="color: black;">&#41;</span>, <span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span><span style="color: black;">&#125;</span><span style="color: black;">&#41;</span>
<span style="color: black;">&#123;</span><span style="color: #483d8b;">'#<span style="color: #000099; font-weight: bold;">\n</span>'</span>: <span style="color: #ff4500;">6</span>,
 <span style="color: #483d8b;">'# / was on /dev/sda7 during installation<span style="color: #000099; font-weight: bold;">\n</span>'</span>: <span style="color: #ff4500;">8</span>,
 <span style="color: #483d8b;">'# /etc/fstab: static file system information.<span style="color: #000099; font-weight: bold;">\n</span>'</span>: <span style="color: #ff4500;">1</span>,
 <span style="color: #483d8b;">'# &lt;file system&gt; &lt;mount point&gt;   &lt;type&gt;  &lt;options&gt;       &lt;dump&gt;  &lt;pass&gt;<span style="color: #000099; font-weight: bold;">\n</span>'</span>: <span style="color: #ff4500;">7</span>,
 <span style="color: #483d8b;">&quot;# Use 'blkid' to print the universally unique identifier for a<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span>: <span style="color: #ff4500;">3</span>,
 <span style="color: #483d8b;">'# device; this may be used with UUID= as a more robust way to name devices<span style="color: #000099; font-weight: bold;">\n</span>'</span>: <span style="color: #ff4500;">4</span>,
 <span style="color: #483d8b;">'# swap was on /dev/sda6 during installation<span style="color: #000099; font-weight: bold;">\n</span>'</span>: <span style="color: #ff4500;">10</span>,
 <span style="color: #483d8b;">'# that works even if disks are added and removed. See fstab(5).<span style="color: #000099; font-weight: bold;">\n</span>'</span>: <span style="color: #ff4500;">5</span>,
 <span style="color: #483d8b;">'UUID=4c0455fb-ff57-466a-8d1f-22b575129f4f none            swap    sw              0       0<span style="color: #000099; font-weight: bold;">\n</span>'</span>: <span style="color: #ff4500;">11</span>,
 <span style="color: #483d8b;">'UUID=4f560031-1058-4eb6-a51e-b7991dfc6db7 /               ext4    errors=remount-ro 0       1<span style="color: #000099; font-weight: bold;">\n</span>'</span>: <span style="color: #ff4500;">9</span>,
 <span style="color: #483d8b;">'UUID=b27f7e93-60c0-4efa-bfae-5ac21a8f4e3c /media/sam ext4 auto,user,rw,exec 0 0<span style="color: #000099; font-weight: bold;">\n</span>'</span>: <span style="color: #ff4500;">12</span><span style="color: black;">&#125;</span></pre></div></div>

<p>Cela dit, on n&#8217;a pas toujours besoin de clés ET de valeurs pour créer un dictionnaire. Ainsi, si on a une liste de n&#8217;clés qu&#8217;on veut toutes initialiser à la même valeur, la très peu connue méthode <code>fromkeys</code> nous rendra bien service :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> personnes = <span style="color: black;">&#40;</span><span style="color: #483d8b;">'Joe'</span>, <span style="color: #483d8b;">'John'</span>, <span style="color: #483d8b;">'Jean-michel'</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #008000;">dict</span>.<span style="color: black;">fromkeys</span><span style="color: black;">&#40;</span>personnes, <span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>
<span style="color: black;">&#123;</span><span style="color: #483d8b;">'Jean-michel'</span>: <span style="color: #ff4500;">0</span>, <span style="color: #483d8b;">'John'</span>: <span style="color: #ff4500;">0</span>, <span style="color: #483d8b;">'Joe'</span>: <span style="color: #ff4500;">0</span><span style="color: black;">&#125;</span></pre></div></div>

<p>De même, on peut ne pas vouloir initialiser un dico, mais vouloir une valeur par défaut pour toutes les clés.  <code>collections.defaultdict</code> est fait pour ça. En plus, les valeurs peuvent être dynamiques :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">from</span> <span style="color: #dc143c;">collections</span> <span style="color: #ff7700;font-weight:bold;">import</span> defaultdict
<span style="color: #66cc66;">&gt;&gt;&gt;</span> scores = defaultdict<span style="color: black;">&#40;</span><span style="color: #ff7700;font-weight:bold;">lambda</span>: <span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> scores<span style="color: black;">&#91;</span><span style="color: #483d8b;">'Joe'</span><span style="color: black;">&#93;</span>
<span style="color: #ff4500;">0</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> scores<span style="color: black;">&#91;</span><span style="color: #483d8b;">'Joe'</span><span style="color: black;">&#93;</span> = <span style="color: #ff4500;">1</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> scores<span style="color: black;">&#91;</span><span style="color: #483d8b;">'Joe'</span><span style="color: black;">&#93;</span>
<span style="color: #ff4500;">1</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> scores<span style="color: black;">&#91;</span><span style="color: #483d8b;">'July'</span><span style="color: black;">&#93;</span>
<span style="color: #ff4500;">0</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">datetime</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> naissances = defaultdict<span style="color: black;">&#40;</span><span style="color: #dc143c;">datetime</span>.<span style="color: #dc143c;">datetime</span>.<span style="color: black;">utcnow</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> naissances<span style="color: black;">&#91;</span><span style="color: #483d8b;">'Joe'</span><span style="color: black;">&#93;</span>
<span style="color: #dc143c;">datetime</span>.<span style="color: #dc143c;">datetime</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">2014</span>, <span style="color: #ff4500;">6</span>, <span style="color: #ff4500;">29</span>, <span style="color: #ff4500;">6</span>, <span style="color: #ff4500;">58</span>, <span style="color: #ff4500;">11</span>, <span style="color: #ff4500;">412202</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Enfin, je sais que tous les tutos du monde en Python utilisent le dictionnaire pour montrer une forme ou une aute de compteur. Mais si vous avez VRAIMENT besoin d&#8217;un compteur, utilisez <code>collections.Counter</code> qui est un objet avec l&#8217;interface d&#8217;un dictionnaire mais avec tout ce qu&#8217;il faut pour compter :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">from</span> <span style="color: #dc143c;">collections</span> <span style="color: #ff7700;font-weight:bold;">import</span> Counter
<span style="color: #66cc66;">&gt;&gt;&gt;</span> c = Counter<span style="color: black;">&#40;</span><span style="color: #483d8b;">'abbbac'</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># comptage automatique</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> c
Counter<span style="color: black;">&#40;</span><span style="color: black;">&#123;</span><span style="color: #483d8b;">'b'</span>: <span style="color: #ff4500;">3</span>, <span style="color: #483d8b;">'a'</span>: <span style="color: #ff4500;">2</span>, <span style="color: #483d8b;">'c'</span>: <span style="color: #ff4500;">1</span><span style="color: black;">&#125;</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> c<span style="color: black;">&#91;</span><span style="color: #483d8b;">'c'</span><span style="color: black;">&#93;</span>
<span style="color: #ff4500;">1</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> c<span style="color: black;">&#91;</span><span style="color: #483d8b;">'d'</span><span style="color: black;">&#93;</span> <span style="color: #808080; font-style: italic;"># pas de KeyError</span>
<span style="color: #ff4500;">0</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> c<span style="color: black;">&#91;</span><span style="color: #483d8b;">'z'</span><span style="color: black;">&#93;</span> += <span style="color: #ff4500;">1</span> <span style="color: #808080; font-style: italic;"># pas de KeyError</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> c<span style="color: black;">&#91;</span><span style="color: #483d8b;">'z'</span><span style="color: black;">&#93;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> c.<span style="color: black;">most_common</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># et en bonus</span>
<span style="color: black;">&#91;</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'b'</span>, <span style="color: #ff4500;">3</span><span style="color: black;">&#41;</span>, <span style="color: black;">&#40;</span><span style="color: #483d8b;">'a'</span>, <span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span></pre></div></div>

<h2>Clé en main</h2>
<p>Récupérer une clé si on ne sait pas si elle est présente est une opération courante, et la documentation montre généralement ça :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">try</span>:
   val = dico<span style="color: black;">&#91;</span><span style="color: #483d8b;">'cle'</span><span style="color: black;">&#93;</span>
<span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">KeyError</span>:
   val = <span style="color: #483d8b;">'valeur par defaut'</span></pre></div></div>

<p>Bien que ce soit parfaitement valide, c&#8217;est généralement se faire chier pour rien puisqu&#8217;on peut faire ça en une ligne :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">   val = dico.<span style="color: black;">get</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'cle'</span>, <span style="color: #483d8b;">'valeur par defaut'</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Néanmoins la méthode <code>get()</code> est très connue. Moins connue est la méthode <code>setdefault</code>. En effet, parfois on veut faire plutôt ceci :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">try</span>:
   val = dico<span style="color: black;">&#91;</span><span style="color: #483d8b;">'cle'</span><span style="color: black;">&#93;</span>
<span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">KeyError</span>:
   dico<span style="color: black;">&#91;</span><span style="color: #483d8b;">'cle'</span><span style="color: black;">&#93;</span> = <span style="color: #483d8b;">'valeur par defaut'</span>
   val = <span style="color: #483d8b;">'valeur par defaut'</span></pre></div></div>

<p>Et ça peut également se faire en une ligne :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">   val = dico.<span style="color: black;">setdefault</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'cle'</span>, valeur par defaut<span style="color: black;">&#41;</span></pre></div></div>

<p>J&#8217;aimerais aussi en profiter pour rappeler que les clés des dicos peuvent être n&#8217;importe quel objet hashable, pas juste une string ou un int. Notamment, <a href="http://sametmax.com/de-linteret-des-tuples-comme-cle-de-dictionnaire/">les tuples sont des clés valides</a>, et comme l&#8217;opérateur tuple <a href="http://sametmax.com/10-trucs-que-je-deteste-en-python/">est la virgule et non la parenthèse</a>, cette syntaxe est parfaitement valide :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> d = <span style="color: black;">&#123;</span><span style="color: black;">&#125;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> d<span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">2</span><span style="color: black;">&#93;</span> = <span style="color: #483d8b;">'tresor'</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> d<span style="color: black;">&#91;</span><span style="color: #ff4500;">3</span>, <span style="color: #ff4500;">3</span><span style="color: black;">&#93;</span> = <span style="color: #483d8b;">'mine'</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> d
<span style="color: black;">&#123;</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span>: <span style="color: #483d8b;">'tresor'</span>, <span style="color: black;">&#40;</span><span style="color: #ff4500;">3</span>, <span style="color: #ff4500;">3</span><span style="color: black;">&#41;</span>: <span style="color: #483d8b;">'mine'</span><span style="color: black;">&#125;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> d<span style="color: black;">&#91;</span><span style="color: #ff4500;">3</span>, <span style="color: #ff4500;">3</span><span style="color: black;">&#93;</span>
<span style="color: #483d8b;">'mine'</span></pre></div></div>

<p>Parmi les objets utilisables comme clés :</p>
<ul>
<li>Les frozenset.</li>
<li>Les <a href="http://sametmax.com/le-namedtuple-la-structure-mal-aimee/">namedtuples</a></li>
<li>Les instances de <a href="http://sametmax.com/le-guide-ultime-et-definitif-sur-la-programmation-orientee-objet-en-python-a-lusage-des-debutants-qui-sont-rassures-par-les-textes-detailles-qui-prennent-le-temps-de-tout-expliquer-partie-1/">vos classes</a></li>
</ul>
<p>Si vous avez un doute, il est facile de savoir si un objet est hashable ou pas :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">collections</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #008000;">isinstance</span><span style="color: black;">&#40;</span><span style="color: black;">&#123;</span><span style="color: black;">&#125;</span>, <span style="color: #dc143c;">collections</span>.<span style="color: black;">Hashable</span><span style="color: black;">&#41;</span>
<span style="color: #008000;">False</span>
<span style="color: #66cc66;">&gt;&gt;</span> <span style="color: #008000;">isinstance</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span>, <span style="color: #dc143c;">collections</span>.<span style="color: black;">Hashable</span><span style="color: black;">&#41;</span>
<span style="color: #008000;">True</span></pre></div></div>

<h2>Mon dico à moi, c&#8217;est le meilleur</h2>
<p>On peut tout à fait hériter du type dictionnaire pour obtenir un type qui a des fonctionnalités que le type original n&#8217;a pas :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">class</span> MonDico<span style="color: black;">&#40;</span><span style="color: #008000;">dict</span><span style="color: black;">&#41;</span>:
...     <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__add__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, other<span style="color: black;">&#41;</span>:
...         <span style="color: #dc143c;">new</span> = <span style="color: black;">&#123;</span><span style="color: black;">&#125;</span>
...         <span style="color: #dc143c;">new</span>.<span style="color: black;">update</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>
...         <span style="color: #dc143c;">new</span>.<span style="color: black;">update</span><span style="color: black;">&#40;</span>other<span style="color: black;">&#41;</span>
...         <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #dc143c;">new</span>
...
<span style="color: #66cc66;">&gt;&gt;&gt;</span> d1 = MonDico<span style="color: black;">&#40;</span>a=<span style="color: #ff4500;">1</span>, b=<span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> d2 = MonDico<span style="color: black;">&#40;</span>b=<span style="color: #ff4500;">3</span>, c=<span style="color: #ff4500;">3</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> d1 + d2
<span style="color: black;">&#123;</span><span style="color: #483d8b;">'a'</span>: <span style="color: #ff4500;">1</span>, <span style="color: #483d8b;">'c'</span>: <span style="color: #ff4500;">3</span>, <span style="color: #483d8b;">'b'</span>: <span style="color: #ff4500;">3</span><span style="color: black;">&#125;</span></pre></div></div>

<p>Mais c&#8217;est assez rare. La plupart du temps on veut plutôt rajouter des fonctionnalités de conteneur à un type existant. Dans ce cas, les <a href="http://sametmax.com/le-guide-ultime-et-definitif-sur-la-programmation-orientee-objet-en-python-a-lusage-des-debutants-qui-sont-rassures-par-les-textes-detailles-qui-prennent-le-temps-de-tout-expliquer-partie-6/">méthodes magiques</a> viennent à la rescousse. Par exemple :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">class</span> Phrase<span style="color: black;">&#40;</span><span style="color: #008000;">object</span><span style="color: black;">&#41;</span>:
&nbsp;
   <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, <span style="color: #dc143c;">string</span><span style="color: black;">&#41;</span>:
      <span style="color: #008000;">self</span>.<span style="color: black;">words</span> = <span style="color: #dc143c;">string</span>.<span style="color: black;">split</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
   <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__getitem__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, word<span style="color: black;">&#41;</span>:
      <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: black;">&#91;</span>i <span style="color: #ff7700;font-weight:bold;">for</span> i, w <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">enumerate</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">words</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">if</span> w == word<span style="color: black;">&#93;</span>
&nbsp;
<span style="color: #66cc66;">&gt;&gt;&gt;</span> p = Phrase<span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Une petite puce pique plus qu'une grosse puce ne pique&quot;</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> p<span style="color: black;">&#91;</span><span style="color: #483d8b;">'petite'</span><span style="color: black;">&#93;</span>
<span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> p<span style="color: black;">&#91;</span><span style="color: #483d8b;">'puce'</span><span style="color: black;">&#93;</span>
<span style="color: black;">&#91;</span><span style="color: #ff4500;">2</span>, <span style="color: #ff4500;">7</span><span style="color: black;">&#93;</span></pre></div></div>

<p>Hey oui, les hash maps en Python, c&#8217;est un sujet qui peut aller très, très loin. C&#8217;est ce qui est merveilleux avec ce langage, on peut rapidement programmer en effleurant juste la surface, sans se noyer. Et si on a besoin d&#8217;aller plus loin, des profondeurs abyssales de features nous attendent.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=11217&amp;md5=7aee6f5b82591cc60c0802185a342dcd" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=11240
title: Rendre un élément scrollable avec Angular
uri: Rendre-un-élément-scrollable-avec-Angular
url: http://sametmax.com/rendre-un-element-scrollable-avec-angular/
content:
<p>Petit snippet que j&#8217;utilise dans mes apps angular. Ça permet de définir un comportement quand l&#8217;utilisateur scrolle au-dessus d&#8217;un élément. Typiquement, augmenter la valeur d&#8217;un champ, faire défiler un carousel, etc. Il faut, bien entendu, éviter que la page scrolle elle-même.</p>
<h2>Implémentation</h2>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">app.<span style="color: #660066;">directive</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'wheelable'</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<span style="color: #3366CC;">&quot;use strict&quot;</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #009966; font-style: italic;">/* On définit sur quels attributs on va mettre les callbacks */</span>
  <span style="color: #003366; font-weight: bold;">var</span> directive <span style="color: #339933;">=</span> <span style="color: #009900;">&#123;</span>
      scope<span style="color: #339933;">:</span> <span style="color: #009900;">&#123;</span>
          <span style="color: #3366CC;">'onWheelUp'</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">'&amp;onwheelup'</span><span style="color: #339933;">,</span>
          <span style="color: #3366CC;">'onWheelDown'</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">'&amp;onwheeldown'</span>
      <span style="color: #009900;">&#125;</span>
  <span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #009966; font-style: italic;">/* On limite la directive aux attributs */</span>
  directive.<span style="color: #660066;">restrict</span> <span style="color: #339933;">=</span> <span style="color: #3366CC;">'A'</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #009966; font-style: italic;">/* Le code qu'active la directive quand on la pose sur l'élément */</span>
  directive.<span style="color: #660066;">link</span> <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>$scope<span style="color: #339933;">,</span> element<span style="color: #339933;">,</span> attributes<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
&nbsp;
      <span style="color: #009966; font-style: italic;">/* On attache un callback à tous les événements de scrolling */</span>
      element.<span style="color: #660066;">bind</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'mousewheel wheel'</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>e<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
&nbsp;
        <span style="color: #009966; font-style: italic;">/* On vérifie si l'utilisateur scroll up ou down */</span>
        <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>e.<span style="color: #660066;">originalEvent</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
          e <span style="color: #339933;">=</span> e.<span style="color: #660066;">originalEvent</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
        <span style="color: #003366; font-weight: bold;">var</span> delta <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>e.<span style="color: #660066;">wheelDelta</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">?</span> e.<span style="color: #660066;">wheelDelta</span> <span style="color: #339933;">:</span> <span style="color: #339933;">-</span>e.<span style="color: #660066;">deltaY</span><span style="color: #339933;">;</span>
        <span style="color: #003366; font-weight: bold;">var</span> isScrollingUp <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>e.<span style="color: #660066;">detail</span> <span style="color: #339933;">||</span> delta <span style="color: #339933;">&gt;</span> <span style="color: #CC0000;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
        <span style="color: #009966; font-style: italic;">/* On appelle le bon callback utilisateur */</span>
        <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>isScrollingUp<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
          $scope.$apply<span style="color: #009900;">&#40;</span>$scope.<span style="color: #660066;">onWheelUp</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span> <span style="color: #000066; font-weight: bold;">else</span> <span style="color: #009900;">&#123;</span>
          $scope.$apply<span style="color: #009900;">&#40;</span>$scope.<span style="color: #660066;">onWheelDown</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
&nbsp;
        <span style="color: #009966; font-style: italic;">/* On évite que la page scrolle */</span>
        e.<span style="color: #660066;">preventDefault</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #000066; font-weight: bold;">return</span> directive<span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<h2>Usage</h2>
<p>Comme pour toutes les directives qui impliquent des callbacks, il faut définir des fonctions et les attacher à votre scope dans un controleur (ou un service attaché au controleur) :</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">app.<span style="color: #660066;">controller</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'FooCtrl'</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>$scope<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<span style="color: #3366CC;">&quot;use strict&quot;</span><span style="color: #339933;">;</span>
  $scope.<span style="color: #660066;">votreCallBackPourQuandCaScrollDown</span> <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
    <span style="color: #006600; font-style: italic;">// faire un truc par exemple moi je l'utilise pour changer</span>
    <span style="color: #006600; font-style: italic;">// la valeur de l'élément.</span>
  <span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
  $scope.<span style="color: #660066;">votreCallBackPourQuandCaScrollDown</span> <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
    <span style="color: #006600; font-style: italic;">// faire un autre truc</span>
  <span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>La directive s&#8217;utilise en mettant l&#8217;attribut <code>wheelable</code> sur l&#8217;élément qu&#8217;on veut rendre scrollable. Ensuite on déclare dans les attributs <code>onwheeldown</code> et <code>onwheelup</code> le code à exécuter, et zou :</p>

<div class="wp_syntax"><div class="code"><pre class="html" style="font-family:monospace;">&lt;div ng-controller=&quot;FooCtrl&quot;&gt;
  ...
  &lt;input type=&quot;text&quot; wheelable
         onwheeldown=&quot;votreCallBackPourQuandCaScrollDown()&quot;
         onwheelup=&quot;votreCallBackPourQuandCaScrollUp()&quot;
         &gt;
  ...
&lt;/div&gt;</pre></div></div>

 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=11240&amp;md5=29355b97b0fef5f95803aacd03c4a2dd" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=10485
title: Pourquoi self en Python ?
uri: Pourquoi-self-en-Python
url: http://sametmax.com/pourquoi-self-en-python/
content:
<p>Quand on écrit une méthode dans une classe en Python, vous êtes obligé de faire ceci :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">class</span> UneClasse:
   <span style="color: #808080; font-style: italic;">#              ?</span>
   <span style="color: #808080; font-style: italic;">#              |</span>
   <span style="color: #808080; font-style: italic;">#              v</span>
   <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
      <span style="color: #008000;">self</span>.<span style="color: black;">attribut</span> = <span style="color: #483d8b;">'value'</span>
&nbsp;
   <span style="color: #808080; font-style: italic;">#                ?</span>
   <span style="color: #808080; font-style: italic;">#                |</span>
   <span style="color: #808080; font-style: italic;">#                v</span>
   <span style="color: #ff7700;font-weight:bold;">def</span> une_methode<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
      <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">attribut</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Vous êtes tenu de déclarer <code>self</code>, le premier paramètre, qui sera l&#8217;instance en cours.</p>
<p>Cela étonne, parfois irrite. Pourquoi dois-je me taper ce <code>self</code> ?</p>
<p>D&#8217;abord, petite clarification : le nom <code>self</code> n&#8217;est qu&#8217;une convention. Le premier paramètre de toutes les méthodes est une instance, soit, mais il n&#8217;a pas de nom obligatoire.</p>
<p>Ce code marche parfaitement :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">class</span> UneClasse:
&nbsp;
   <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span>tachatte<span style="color: black;">&#41;</span>:
      tachatte.<span style="color: black;">attribut</span> = <span style="color: #483d8b;">'value'</span>
&nbsp;
   <span style="color: #ff7700;font-weight:bold;">def</span> une_methode<span style="color: black;">&#40;</span>tachatte<span style="color: black;">&#41;</span>:
      <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>tachatte.<span style="color: black;">attribut</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Il ne passera probablement pas une code review, mais il est valide.</p>
<p>Il ne passera pas une code review, non pas parce que <code>tachatte</code> n&#8217;est pas un nom de variable politiquement correcte &#8211; après tout ces mignonnes boules de poils ne sont-elles pas aimées par tous ? &#8211; mais parce que <code>self</code> est une convention forte. Tellement forte que les éditeurs de code la prennent en compte.</p>
<p>Mais je suppose que la plus grosse interrogation, c&#8217;est pourquoi on se tape le <code>self</code> à la main, et pas :</p>
<ul>
<li>Rien comme en C++ ?</li>
<li><code>@</code> comme en ruby ?</li>
<li><code>this</code> comme en JS ?</li>
<li><code>$this</code> comme en PHP ?</li>
</ul>
<p>Il y a de nombreuses raisons.</p>
<p>D&#8217;abord, rien comme le C++ ne permettrait pas, en Python, de distinguer une variable locale d&#8217;une variable d&#8217;un scope supérieur, rendant la lecture difficile. La philosophie de Python étant qu&#8217;on lit un code 100 fois plus qu&#8217;on l&#8217;écrit et qu&#8217;il faut donc faciliter la lecture plutôt que l&#8217;écriture, cela n&#8217;a pas été retenu.</p>
<p><code>@</code> comme en Ruby suppose 3 notations. <code>@</code> pour les variables d&#8217;instance, <code>@@</code> pour les variables de classe, et <code>self</code> pour l&#8217;instance en cours (avec un usage aussi pour définir les méthodes de classe car les classes sont des instances, mais je trouve ça super bordélique). Ça introduit beaucoup de mécanismes supplémentaires pour utiliser quelque chose qui existe déjà, et comme en la philosophie de Python c&#8217;est qu&#8217;il ne devrait y avoir qu&#8217;un seul moyen, de préférence évident, de faire quelques chose, utiliser juste une référence aux classes et aux instances a été choisi.</p>
<p>Pour le JS, et son binding de merde, je vais passer mon tour, sinon je vais encore m&#8217;énerver.</p>
<p>Reste donc la solution de PHP, Java, etc., une référence explicite <code>this</code>, mais automatiquement présente dans le scope de la méthode.</p>
<p>La réponse courte, est encore une fois philosophique. En Python, on préfère l&#8217;explicite plutôt que l&#8217;implicite.</p>
<p>Si vous avez ce code :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">class</span> UneClasse:
&nbsp;
   <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
      <span style="color: #008000;">self</span>.<span style="color: black;">attribut</span> = <span style="color: #483d8b;">'value'</span>
&nbsp;
   <span style="color: #ff7700;font-weight:bold;">def</span> une_methode<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
      <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">attribut</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Et que vous faites :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">instance = UneClasse<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
instance.<span style="color: black;">une_methode</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>En réalité vous faites sans le savoir :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">instance = UneClasse<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
UneClasse.<span style="color: black;">une_methode</span><span style="color: black;">&#40;</span>instance<span style="color: black;">&#41;</span></pre></div></div>

<p>L&#8217;interpréteur fait la conversion pour vous (il y a derrière une notion de bound/unbound, mais c&#8217;est un autre sujet).</p>
<p>A l&#8217;appel de la &#8220;méthode&#8221;, <code>instance</code> est visiblement présente, c&#8217;est assez explicite, et plus court que la version traduite par l&#8217;interpréteur. Donc Python vous aide avec cette traduction. Mais au niveau de la déclaration de la méthode, il n&#8217;y a pas de mention explicite de la référence à la variable d&#8217;instance, donc Guido <a href="https://docs.python.org/2/faq/design.html#why-must-self-be-used-explicitly-in-method-definitions-and-calls">a choisi</a>, comme en Modula-3, de rendre le passage explicite.</p>
<p>Ce comportement a tout un tas de conséquences forts pratiques.</p>
<p>Python a en effet une fonctionnalité que PHP et Java n&#8217;ont pas : l&#8217;héritage multiple. Dans ce contexte, le passage explicite du <code>self</code> permet de facilement choisir l&#8217;appel de la méthode d&#8217;un parent, sans faire appel à des mécanismes supplémentaires (C++ ajoute par exemple un opérateur pour ça):</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">class</span> Clerc:
   heal = <span style="color: #ff4500;">50</span>
   <span style="color: #ff7700;font-weight:bold;">def</span> soigner<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
      <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>.<span style="color: black;">heal</span> <span style="color: #66cc66;">*</span> <span style="color: #ff4500;">2</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> Paladin:
   heal = <span style="color: #ff4500;">60</span>
   <span style="color: #ff7700;font-weight:bold;">def</span> soigner<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
      <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>.<span style="color: black;">heal</span> <span style="color: #66cc66;">*</span> <span style="color: #ff4500;">1.5</span> + <span style="color: #ff4500;">30</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> BiClasse<span style="color: black;">&#40;</span>Clerc, Paladin<span style="color: black;">&#41;</span>:
   heal = <span style="color: #ff4500;">55</span>
   <span style="color: #ff7700;font-weight:bold;">def</span> soigner<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
      <span style="color: #808080; font-style: italic;"># Hop, j’appelle les parents distinctement</span>
      <span style="color: #808080; font-style: italic;"># et fastochement en prenant la méthode</span>
      <span style="color: #808080; font-style: italic;"># au niveau de la classe, et en lui passant</span>
      <span style="color: #808080; font-style: italic;"># manuellement l'instance.</span>
      soin_clerc = Clerc.<span style="color: black;">soigner</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>
      soin_palouf = Paladin.<span style="color: black;">soigner</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>
      <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: black;">&#40;</span>soin_clerc + soin_palouf<span style="color: black;">&#41;</span> / <span style="color: #ff4500;">2</span></pre></div></div>

<p>Mais, et peu de gens le savent, il permet aussi de faire de la composition  beaucoup plus fine, en ignorant complètement l&#8217;héritage.</p>
<p>On peut notamment créer des algo globaux, et ensuite les attacher à des objets:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">&nbsp;
<span style="color: #808080; font-style: italic;"># Une fonction moyenne qui fonctionne de manière générique</span>
<span style="color: #808080; font-style: italic;"># et utilisable normalement. Imaginez que cela puisse être</span>
<span style="color: #808080; font-style: italic;"># un algo complexe. On veut pouvoir l'utiliser hors du</span>
<span style="color: #808080; font-style: italic;"># cadre d'objet.</span>
<span style="color: #ff7700;font-weight:bold;">def</span> moyenne<span style="color: black;">&#40;</span>sequence<span style="color: black;">&#41;</span>:
   <span style="color: #483d8b;">&quot;&quot;&quot; Calcule la moyenne d'une séquence.
&nbsp;
       Les décimales sont tronquées
   &quot;&quot;&quot;</span>
   notes = <span style="color: #008000;">list</span><span style="color: black;">&#40;</span>sequence<span style="color: black;">&#41;</span>
   <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">sum</span><span style="color: black;">&#40;</span>notes<span style="color: black;">&#41;</span> / <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>notes<span style="color: black;">&#41;</span>
&nbsp;
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> DossierEleve:
&nbsp;
   <span style="color: #808080; font-style: italic;"># Intégration de l'algo de la fonction &quot;moyenne&quot;</span>
   <span style="color: #808080; font-style: italic;"># à notre dossier, sans se faire chier à faire</span>
   <span style="color: #808080; font-style: italic;"># un héritage. Comme 'self' est passé en premier</span>
   <span style="color: #808080; font-style: italic;"># paramètre, 'sequence' contiendra 'self'. Comme</span>
   <span style="color: #808080; font-style: italic;"># plus bas on rend le dossier itérable, tout va</span>
   <span style="color: #808080; font-style: italic;"># marcher.</span>
   moyenne = moyenne
&nbsp;
   <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
      <span style="color: #008000;">self</span>.<span style="color: black;">notes</span> = <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>
&nbsp;
   <span style="color: #808080; font-style: italic;"># on rend le dossier itérable</span>
   <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__iter__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
      <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">iter</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">notes</span><span style="color: black;">&#41;</span>
&nbsp;
   <span style="color: #808080; font-style: italic;"># on donne une taille au dossier</span>
   <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__len__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
      <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">len</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">notes</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># On peut l'intégrer à plusieurs classes.</span>
<span style="color: #ff7700;font-weight:bold;">class</span> CarnetDeClasse:
&nbsp;
   moyenne = moyenne
&nbsp;
   <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
      <span style="color: #008000;">self</span>.<span style="color: black;">notes</span> = <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>
&nbsp;
   <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__iter__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
      <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">iter</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">notes</span><span style="color: black;">&#41;</span>
&nbsp;
   <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__len__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
      <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">len</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">notes</span><span style="color: black;">&#41;</span>
&nbsp;
c = CarnetDeClasse<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
c.<span style="color: black;">notes</span> = <span style="color: black;">&#91;</span><span style="color: #ff4500;">12</span>, <span style="color: #ff4500;">14</span>, <span style="color: #ff4500;">13</span>, <span style="color: #ff4500;">15</span><span style="color: black;">&#93;</span>
<span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>c.<span style="color: black;">moyenne</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #808080; font-style: italic;">## 13</span>
e = DossierEleve<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
e.<span style="color: black;">notes</span> = <span style="color: black;">&#91;</span><span style="color: #ff4500;">9</span>, <span style="color: #ff4500;">8</span>, <span style="color: #ff4500;">17</span>, <span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span>
<span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>e.<span style="color: black;">moyenne</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #808080; font-style: italic;">## 8</span></pre></div></div>

<p>Vous allez me dire, pourquoi ne pas faire <code>moyenne(eleve)</code> dans ces cas ? Parce que ce code supposerait connaitre de l&#8217;implémentation d&#8217;élève. Alors que <code>eleve.moyenne()</code> utilise le code encapsulé, sans avoir à s&#8217;en soucier. Si le code change (ce qui arrive dans des cas plus complexes qu&#8217;une moyenne), pas besoin de changer son API.</p>
<p>Vous me direz, si on avait pas le <code>self</code> explicite, on pourrait faire ça :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">class</span> DossierEleve:
   <span style="color: #ff7700;font-weight:bold;">def</span> moyenne<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
      <span style="color: #ff7700;font-weight:bold;">return</span> moyenne<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Mais :</p>
<ul>
<li>C&#8217;est plus verbeux.</li>
<li>C&#8217;est un look up supplémentaire.</li>
<li>On perd l&#8217;introspection de <code>moyenne()</code>.</li>
<li>On perd la docstring de <code>moyenne()</code>.</li>
<li>On perd tous les attributs attachés à <code>moyenne()</code> (si moyenne est un objet avec une méthode <code>__call__</code>, vous n&#8217;y avez plus accès depuis l&#8217;extérieur).</li>
<li>Si la fonction avait plus de paramètres, il faut lui repasser à la main. <code>Moyenne()</code> est une fonction très simple.</li>
<li>Si moyenne fait de l&#8217;instrospection de stack, vous allez fausser son analyse.</li>
<li>Ça rajoute un step si on lance le debugger. Et une ligne inutile dans la stack trace.</li>
<li>Ça ne marche pas si <code>moyenne</code> est une fonction éphémère, dynamiquement créée, car on n&#8217;a pas de référence à la fonction et le code va planter.</li>
</ul>
<p>En Python 3, ça va même plus loin. Ce <code>self</code> explicite permet également de partager du code entre objets, sans utiliser l&#8217;héritage.</p>
<p>Imaginez un autre scénario, où vous importez une lib <em>gestion_classe.py</em>, qui n&#8217;est pas votre code. Vous savez que son algo de calcul de moyenne est très complexe, mais très rapide, et efficace, et vous voulez en bénéficier. Seulement, il est encapsulé dans la classe <code>CarnetDeClasse</code>, et en faire hériter un profil d&#8217;élève d&#8217;un carnet de classe n&#8217;a absolument aucun sens.</p>
<p>Dans <em>gestion_classe.py</em> :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">class</span> CarnetDeClasse:
&nbsp;
   <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
      <span style="color: #008000;">self</span>.<span style="color: black;">notes</span> = <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>
&nbsp;
   <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__iter__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
      <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">iter</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">notes</span><span style="color: black;">&#41;</span>
&nbsp;
   <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__len__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
      <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">len</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">notes</span><span style="color: black;">&#41;</span>
&nbsp;
   <span style="color: #ff7700;font-weight:bold;">def</span> moyenne<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
      notes = <span style="color: #008000;">list</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>
      <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">sum</span><span style="color: black;">&#40;</span>notes<span style="color: black;">&#41;</span> // <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>notes<span style="color: black;">&#41;</span></pre></div></div>

<p>Et dans votre code :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">&nbsp;
<span style="color: #ff7700;font-weight:bold;">from</span> gestion_classe <span style="color: #ff7700;font-weight:bold;">import</span> CarnetDeClasse
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> DossierEleve:
&nbsp;
   moyenne = CarnetDeClasse.<span style="color: black;">moyenne</span>
&nbsp;
   <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
      <span style="color: #008000;">self</span>.<span style="color: black;">notes</span> = <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>
&nbsp;
   <span style="color: #808080; font-style: italic;"># on rend le dossier itérable</span>
   <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__iter__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
      <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">iter</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">notes</span><span style="color: black;">&#41;</span>
&nbsp;
   <span style="color: #808080; font-style: italic;"># on donne une taille au dossier</span>
   <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__len__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
      <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">len</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">notes</span><span style="color: black;">&#41;</span>
&nbsp;
e = DossierEleve<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
e.<span style="color: black;">notes</span> = <span style="color: black;">&#91;</span><span style="color: #ff4500;">9</span>, <span style="color: #ff4500;">8</span>, <span style="color: #ff4500;">17</span>, <span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span>
<span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>e.<span style="color: black;">moyenne</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #808080; font-style: italic;">## 8</span></pre></div></div>

 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=10485&amp;md5=74dd08bcb503b70f363f7bf54c7e9411" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=11268
title: Le merci du jour
uri: Le-merci-du-jour
url: http://sametmax.com/le-merci-du-jour/
content:
<p>Régulièrement je relis les commentaires et je me dis qu&#8217;on a quand même un public en or.</p>
<p>Alors, je me repète, mais merci.</p>
<p>On a peu de trolls ou de connards. </p>
<p>On a des <a href="http://sametmax.com/le-dossier-sur-la-poo-fait-peau-neuve/">relecteurs</a> qu&#8217;ils sont cool.</p>
<p>Et je note aussi la patience que vous avez à me corriger quand j&#8217;écris des conneries. Avec beaucoup de politesse et de cordialité. Et pas juste pour les typos.</p>
<p>J&#8217;apprécie également les débats qu&#8217;on peut avoir, qui peuvent monter en sauce sans jamais exploser. </p>
<p>Merci, donc.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=11268&amp;md5=96a47285456372fe1df38fae32cd55b7" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=11259
title: WAMP et les outils de dev Web Python existants
uri: WAMP-et-les-outils-de-dev-Web-Python-existants
url: http://sametmax.com/wamp-et-les-outils-de-dev-web-python-existants/
content:
<p>Même si on peut créer un site Web en utilisant uniquement des libs WAMP, tout comme on peut le faire en utilisant uniquement flask ou tornado, il arrive immanquablement le moment où on veut mélanger, intégrer, faire cohabiter les techos ensemble. D&#8217;abord parce qu&#8217;il y a des sites existants, et qu&#8217;on va pas les jeter à la poubelle. Ensuite parce que ce sont des techos qu&#8217;on connaît et pour lesquelles ils y a beaucoup d&#8217;outils, que l&#8217;on veut mettre à profit.</p>
<p>C&#8217;est tout naturellement qu&#8217;on a fini par me poser (par mail), ze question :</p>
<blockquote><p>Subject: crossabar et autobahn</p>
<p>Message Body:<br />
Ha bah oui vous l&#8217;avez cherché à nous parler de truc comme ça: ça interroge !</p>
<p>Je m&#8217;interroge donc sur la manière d&#8217;intégrer WAMP à django. Pour la perstistence des données (l&#8217;ORM qui simplifie la création des tables tout de même), pour l&#8217;authentication et l&#8217;authorization, pour la robustesse et versatilité apportée par django&#8230;</p>
<p>J&#8217;ai pour habitude de mettre pas mal de logique dans mes modèles et je me demandais si il n&#8217;y aurait pas moyen de pluguer WAMP dans ceux ci&#8230; exposer une méthode update en RPC avec passage de JSON ? Avec namespace automatique à partir de la classe ? </p>
<p>En fait remplacer: Angular+tastypie+django+nginx par Angular+WAMP+django+crossbar avec du coup le bonus de WAMP pour le pubsub que n&#8217;a pas AJAX.</p>
<p>Comment vous verriez un (petit &#8211; après relecture ça parait dur) mixin WAMP pour des modèles django auto-détectés, auto-exposés en RPC ?</p>
<p>J&#8217;ai du mal à voir quelle tactique utiliser. J&#8217;ai peur que ça finisse en refaire tout le travail que fait déjà (très bien) tastypie/RESTframework.</p>
<p>Comment modulariser (là ou est sensé briller WAMP) les services déjà offerts par django: celery, authentication, etc ?<br />
Ces services sont tous très dépendant du système de persistance des données (check des users, permissions, query) et donc l&#8217;approche plus monolithique de django n&#8217;est pas mauvaise car tout est lié et donc facilement manipulable au même endroit&#8230; où est le gain de WAMP dans ce cas, pour une application assez classique en fait ?</p>
<p>Merci encore pour cette découverte dans tous les cas. C&#8217;est top.</p>
<p>Du coup je me relis et ça part un peu dans tous les sens&#8230; désolé.</p>
</blockquote>
<p>Comme je me suis fendu d&#8217;une réponse bien longue, je vais la paster verbatim :</p>
<blockquote><p>
Bonjour,</p>
<p>C&#8217;est une très bonne question.</p>
<p>D&#8217;abord, il faut savoir qu&#8217;on ne peut pas faire tourner un routeur WAMP dans un process Django (ou tout autre app WSGI) car Django est synchrone. En plus, l&#8217;ORM de django est bloquant, donc même sans utiliser django, utiliser son ORM au sein de WAMP va bloquer la boucle d&#8217;événements et on perdra tout l&#8217;interêt d&#8217;avoir une techno temps réel.</p>
<p>(Note a posteriori : y a surement un truc à faire avec gevent ou des threads ici, mais je sais pas encore quoi)</p>
<p>Ici on a donc 3 problèmes à résoudre :</p>
<p>- comment faire communiquer django et son app WAMP ?<br />
- comment utiliser un ORM bloquant avec WAMP ?<br />
- comment auto générer une API WAMP ?</p>
<p>Ces 3 questions n&#8217;ont pas encore de réponse définitive puisque, comme je l&#8217;ai précisé, WAMP est une techno jeune, et donc il y a beaucoup à faire. Mes articles sont précisément là pour tenter de générer un enthousiasme et pousser les gens à améliorer les outils autour de WAMP.</p>
<p>Prenons les problèmes un par un :</p>
<p>Comment faire communiquer django et son app WAMP ?<br />
====================================</p>
<p>C&#8217;est le problème le plus facile à mon sens. Il faut coder une app WAMP qui fasse le bridge entre HTTP et WAMP. Quand on register côté app HTTP, on fait un post sur l&#8217;app WAMP (qui écoute aussi sur HTTP du coup) en fournissant une URL de callback. L&#8217;app WAMP fait le register, et quand on l&#8217;appelle, elle fait l&#8217;appel à l&#8217;app HTTP via l&#8217;url de callback, et retourne le résultat. On peut faire ça pour register, subscribe, call et publish, c&#8217;est le même principe.</p>
<p>(Note a posteriori : en me relisant moi-même je m&#8217;aperçois à quel point c&#8217;est pas clair. De toute façon il faudra que je le code un jour où l&#8217;autre, et avec un bon tuto pratique, la pilule passera mieux).</p>
<p>Ce faisant, on pourra appeler du WAMP côté app HTTP, et taper dans l&#8217;app HTTP côté client WAMP.</p>
<p>Une amorce de travail  a été fait pour coder un tel bridge. Pour le moment il n&#8217;y a que le publish :</p>
<p>https://groups.google.com/forum/#!searchin/autobahnws/http/autobahnws/SbobAnoWVlQ/FnGhdYXj9aIJ</p>
<p>Ce n&#8217;est pas très dur à coder, c&#8217;est juste un boulot chiant à faire.</p>
<p>Cela dit, ça ne résout pas le problème de l&#8217;authentification, qu&#8217;il faudra à un moment on un autre, se poser. Je pense qu&#8217;on va se diriger vers une authentification hybride, qui va utiliser le session ID en cookie, mais l&#8217;envoyer via un token. Encore un truc à travailler.</p>
<p>De même, on voudra sûrement créer quelques facilités pour intégrer ça dans les frameworks les plus connus en proposant une app prêt à plugger. Rien d&#8217;insurmontable donc, mais pas mal de taff.</p>
<p>Par contre, pour ce qui est des tasks queues, à mon avis une solution de task queue WAMP sera bien plus intéressante qu&#8217;une solution type celery car on peut envoyer des messages WAMP depuis les tâches et donc avertir en temps réel de l&#8217;avancement du process. Je voterais donc pour coder soi-même une alternative.</p>
<p>Comment utiliser un ORM bloquant avec WAMP ?<br />
===============================</p>
<p>Idéalement, il faudrait avoir des ORM non bloquant, mais on Python, on en a pas. On a quelques drivers non bloquant, notamment pour PostGres et Mongo, mais pas d&#8217;ORM, et ils demandent une forme de compilation d&#8217;extension C.</p>
<p>C&#8217;est là qu&#8217;on voit qu&#8217;on se traine la culture de l&#8217;API synchrone en Python, car côté NodeJS, ils commencent à avoir pas mal de solutions.</p>
<p>En l’occurrence, on a 3 solutions :</p>
<p>- utiliser le bridge dont je viens de parler pour garder les appels dans l&#8217;app HTTP.  Ca veut dire que quand on veut faire un appel à de la base de données, ça fait WAMP => HTTP => connexion à la base, aller-retour. C&#8217;est pas idéal.<br />
- créer une app WAMP pour héberger les appels bloquants et taper dedans en RPC. Une bonne solution à mon avis. Mais assez peu intuitive.<br />
- faire tous les appels dans un threads à part. Le plus simple. Un peu verbeux par contre.</p>
<p>Dans les deux derniers cas, on à quand même le problème des querysets qui sont lazy, notamment au niveau des foreign keys. Il faudra faire particulièrement attention à ne pas accidentellement faire des appels bloquant, par exemple dans le rendu du template. Une solution viable est de créer un wrapper qui fait le rendu du template dans un threads.</p>
<p>Bref, encore pas mal d&#8217;outils à developper.</p>
<p>On peut aussi se lancer dans l&#8217;écriture d&#8217;un ORM non bloquant. Une bonne année de travail avant d&#8217;avoir quelque chose qui soit compétitif.</p>
<p>Comment auto générer une API WAMP ?<br />
==========================</p>
<p>Là tu m&#8217;en poses une bonne.</p>
<p>C&#8217;est la suite logique, évidement, mais je n&#8217;avais jamais réfléchi aussi loin. C&#8217;est un taff énorme, surtout que ça dépend de l&#8217;outil derrière. La solution la plus simple c&#8217;est encore de faire un mapper dans le bridge HTTP-WAMP qui va traduire directement un appel WAMP en un appel JSON vers l&#8217;API générée par django-rest-framework ou autre.</p>
<p>Mais bon, je suis pas certains de la valeur ajoutée.</p>
<p>Je pense qu&#8217;il est difficile pour moi de répondre à cette question pour le moment car :</p>
<p>- je ne suis pas certain que WAMP soit un bon remplacement pour les API REST. Je pense plutôt que c&#8217;est un complément.<br />
- il y a toute la question de l&#8217;authentification. Encore et toujours.<br />
- il va falloir pas mal d&#8217;essais avec plusieurs architectures en prod (séparées, mixtes, mono culture&#8230;) pour pouvoir déterminer ce qui rend le mieux.</p>
<p>Mon intuition est qu&#8217;on utilise généralement 10% de l&#8217;API générée par les frameworks, et que la partie dont on a besoin à peut très bien se faire à la main. La raison pour laquelle les trucs comme django-rest-framework sont si pratiques, c&#8217;est qu&#8217;ils gèrent des problématiques comme l&#8217;authentification, la sérialisation et la pagination.</p>
<p>Je serais plutôt d&#8217;avis de s&#8217;attaquer à ça pour WAMP, et je pense qu&#8217;on s’apercevra que finalement, pour ses propres besoins, un API complète est overkill. Par contre, pour exposer une API au monde, c&#8217;est une autre histoire. J&#8217;ai eu récemment une discussion à propos de faire des APIs WAMP :) Il y a des possibilités fascinantes. Mais c&#8217;est peut être encore un peu loin tout ça.</p>
<p>Je pense que je vais publier cette réponse sur le blog, car tu soulèves des points très importants.</p></blockquote>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=11259&amp;md5=c07cd33c2e542aaa29fda45a947144a8" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


