# articles

feed_id: http://sametmax.com/?p=15797
title: Utiliser requests de manière non bloquante facilement 6
uri: Utiliser-requests-de-manière-non-bloquante-facilement
url: http://sametmax.com/utiliser-requests-de-maniere-non-bloquante-facilement/
content:
<p>En attendant le dossier sur la programmation non bloquante, voici une petite lib qui résout un cas d&#8217;école : faire une requête HTTP sans bloquer avec une jolie API, en pur Python.</p>
<p>Pour ça, on dégaine <a href="http://sametmax.com/votre-python-aime-les-pip/">pip</a> et installe <a href="https://pypi.python.org/pypi/requests-futures/0.9.0">requests-futures</a>, un plugin pour la célèbre lib <a href="http://sametmax.com/sept-petites-libs-qui-changent-la-vie-dun-dev-python/">requests</a> qui fonctionne avec Python 2 et 3 :</p>

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

<p>requests-futures va créer pour vous une pool de workers (2 par défaut) et quand vous faites une requête, la lib vous retourne un objet <a href="http://sametmax.com/deferred-future-et-promise-le-pourquoi-le-comment-et-quand-est-ce-quon-mange/">future</a> qui vous permet d&#8217;attacher un <a href="http://sametmax.com/quest-ce-quun-callback/">callback</a>.</p>
<p>Fiou, le nombre de liens référant à d&#8217;autres articles du blog est en train d&#8217;exploser.</p>
<p>Exemple :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">time</span>
<span style="color: #ff7700;font-weight:bold;">from</span> requests_futures.<span style="color: black;">sessions</span> <span style="color: #ff7700;font-weight:bold;">import</span> FuturesSession
&nbsp;
<span style="color: #808080; font-style: italic;"># Cette session est notre point d'entrée, c'est elle</span>
<span style="color: #808080; font-style: italic;"># qui gère nos workers. Faites help(FuturesSession)</span>
<span style="color: #808080; font-style: italic;"># pour voir ses paramètres.</span>
session <span style="color: #66cc66;">=</span> FuturesSession<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Les URLs sur lesquelles on va faire</span>
<span style="color: #808080; font-style: italic;"># nos requêtes</span>
URLs <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span>
    <span style="color: #483d8b;">&quot;http://sametmax.com&quot;</span><span style="color: #66cc66;">,</span>
    <span style="color: #483d8b;">&quot;http://sebsauvage.net&quot;</span><span style="color: #66cc66;">,</span>
    <span style="color: #483d8b;">&quot;http://indexerror.net&quot;</span><span style="color: #66cc66;">,</span>
    <span style="color: #483d8b;">&quot;http://afpy.org&quot;</span><span style="color: #66cc66;">,</span>
    <span style="color: #483d8b;">&quot;http://0bin.net&quot;</span>
<span style="color: black;">&#93;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Notre callback qui sera appelé quand une </span>
<span style="color: #808080; font-style: italic;"># des requêtes sera terminée. Il reçoit</span>
<span style="color: #808080; font-style: italic;"># l'objet future pour seul paramètre</span>
<span style="color: #ff7700;font-weight:bold;">def</span> faire_un_truc_avec_le_resultat<span style="color: black;">&#40;</span>future<span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;"># On est juste intéressé par le résutlat, qui</span>
    <span style="color: #808080; font-style: italic;"># est un objet response typique de la lib</span>
    <span style="color: #808080; font-style: italic;"># request</span>
    response <span style="color: #66cc66;">=</span> future.<span style="color: black;">result</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>response.<span style="color: black;">url</span><span style="color: #66cc66;">,</span> response.<span style="color: black;">status_code</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># On traite chaque URL. Comme on a 2 workers,</span>
<span style="color: #808080; font-style: italic;"># on pourra traiter au mieux 2 URLs en parallèle,</span>
<span style="color: #808080; font-style: italic;"># mais toujours sans bloquer le programme</span>
<span style="color: #808080; font-style: italic;"># principal</span>
<span style="color: #ff7700;font-weight:bold;">for</span> url <span style="color: #ff7700;font-weight:bold;">in</span> URLs:
    <span style="color: #808080; font-style: italic;"># On fait notre requête GET</span>
    future <span style="color: #66cc66;">=</span> session.<span style="color: black;">get</span><span style="color: black;">&#40;</span>url<span style="color: black;">&#41;</span>
    <span style="color: #808080; font-style: italic;"># On rajoute le callback à appeler quand</span>
    <span style="color: #808080; font-style: italic;"># le résultat de la requête arrive.</span>
    <span style="color: #808080; font-style: italic;"># La flemme de faire la gestion des erreurs.</span>
    future.<span style="color: black;">add_done_callback</span><span style="color: black;">&#40;</span>faire_un_truc_avec_le_resultat<span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Juste pour montrer que c'est bien non bloquant</span>
<span style="color: #ff7700;font-weight:bold;">for</span> x <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">10</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>x<span style="color: black;">&#41;</span>
    <span style="color: #dc143c;">time</span>.<span style="color: black;">sleep</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Output :</p>
<pre>0
1
(u'http://sebsauvage.net/', 200)
(u'http://sametmax.com/', 200)
2
(u'http://indexerror.net/', 200)
(u'http://0bin.net/', 200)
(u'http://www.afpy.org/', 200)
3
4
5
6
7
8
9</pre>
<p>On remerciera turgon37 pour <a href="http://indexerror.net/357/comment-passer-une-valeur-entre-threads">sa question</a> sur IndexError qui m&#8217;a amené à écrire cet article.</p>


feed_id: http://sametmax.com/?p=15806
title: Twisted et requests 8
uri: Twisted-et-requests-1
url: http://sametmax.com/twisted-et-requests/
content:
<p>Utiliser les outils de Twisted de base pour faire les requêtes est assez chiant, et quand on est habitué à <a href="http://docs.python-requests.org/en/latest/">requests</a>, c&#8217;est le retour au moyen age.</p>
<p>La lib <a href="https://github.com/dreid/treq">treq</a> tente de corriger ça mais n&#8217;utilise pas l&#8217;API de requests et ne propose pas certaine de ses fonctionnalités.</p>
<p>Du coup, après <a href="http://sametmax.com/utiliser-requests-de-maniere-non-bloquante-facilement/">l&#8217;article d&#8217;hier,</a> j&#8217;ai regardé le code source de requests-futures pour voir si je pouvais pas faire la même chose pour Twisted.</p>
<p>Et on peut. J&#8217;ai fais un petit (bon, ok minuscule)  wrapper qui permet de faire ça :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">    <span style="color: #ff7700;font-weight:bold;">from</span> requests_twisted <span style="color: #ff7700;font-weight:bold;">import</span> TwistedRequestsSession
    session <span style="color: #66cc66;">=</span> TwistedRequestsSession<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    defer <span style="color: #66cc66;">=</span> session.<span style="color: black;">get</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'http://github.com/sametmax/'</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> print_status<span style="color: black;">&#40;</span>response<span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>response.<span style="color: black;">url</span><span style="color: #66cc66;">,</span> response.<span style="color: black;">status_code</span><span style="color: black;">&#41;</span>
    defer.<span style="color: black;">addCallback</span><span style="color: black;">&#40;</span>print_status<span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Ça utilise l&#8217;objet <a href="http://docs.python-requests.org/en/latest/user/advanced/">Session</a> de requests et donc on peut faire <code>session.get|post|touslestrucsderequests</code> et toute l&#8217;API est disponible.</p>
<p>Donc si vous en avez besoin :</p>

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

<p>Le truc fait 3 lignes et 2 tests unittaires, en fait c&#8217;est juste un <code>deferToThreads</code> derrière. C&#8217;est certain que c&#8217;est moins performant que l&#8217;approche de treq qui utilise directement l&#8217;Agent non bloquant de Twisted, mais pour la plupart des cas c&#8217;est juste plus pratique, plus familier, et surtout, plus facile à maintenir :)</p>


feed_id: http://sametmax.com/?p=15817
title: Écouter sur le port 80 sans être root 16
uri: Écouter-sur-le-port-80-sans-être-root-4-Recently-updated
url: http://sametmax.com/ecouter-sur-le-port-80-sans-etre-root/
content:
<p>Sous beaucoup d&#8217;OS, tous les ports d&#8217;un nombre inférieur à 1024 ne peuvent pas être utilisés par des processus sans avoir les privilèges administrateurs. Néanmoins, on a pas vraiment envie que son app bricolée un lendemain de cuite soit lancée en root, pour que la moindre faille de sécurité donne l&#8217;accès total à son système.</p>
<p>Beaucoup de logiciels se lancent en root, et relâchent leurs privilèges a posteriori. C&#8217;est ce que faisait Apache a une époque (peut être le fait-il toujours, j&#8217;ai pas cheché). Nginx lui, lance un processus racine en root, et spawn des enfants avec un utilisateur normal. </p>
<p>Mais nous, on a pas la foi de se faire chier à faire ça, donc généralement, on met nginx en front et il gère ça pour nous. </p>
<p>Sauf que, parfois, on a pas envie de mettre 40 couches devant notre app. Par exemple, si on utilise crossbar.io (ouai, j&#8217;ai encore réussi à le placer \o/), le logiciel est clairement capable d&#8217;être en front tout seul. </p>
<p>Bonne nouvelle, sur les Linux modernes, les exécutables peuvent avoir des <a href="http://linux.die.net/man/7/capabilities">permissions</a> avancées, comme &#8220;pourvoir changer l&#8217;horloge système&#8221; ou &#8220;empêcher la mise en veille&#8221;. Ces permissions sont changeables avec l&#8217;outil <code>setcap</code>.</p>
<p>Sous Ubuntu, ça s&#8217;installe avec :</p>

<div class="wp_syntax"><table><tr><td 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 install</span> libcap2-bin</pre></td></tr></table></div>

<p>Puis on choisit l&#8217;exécutable à qui on veut donner nos nouvelles permissions. Dans mon cas, le Python du virtualenv de mon projet :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">$ pew workon super_projet
$ which python
/home/sam/.<span style="color: black;">local</span>/share/virtualenvs/super_projet/bin/python</pre></td></tr></table></div>

<p>Je check si il a pas déjà des permissions (normalement non) :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">$ sudo getcap `which python`</pre></td></tr></table></div>

<p>Nada. Good.</p>
<p>Un petit coup de <code>man setcap</code> nous liste les permissions utilisables, et on peut voire que <code>CAP_NET_BIND_SERVICE</code> est la permission qui permet d&#8217;autoriser un exécutable à binder n&#8217;importe quel port. </p>
<p>On rajoute les permissions :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">sudo</span> setcap <span style="color: #007800;">cap_net_bind_service</span>=+ep <span style="color: #000000; font-weight: bold;">`</span><span style="color: #c20cb9; font-weight: bold;">which</span> python<span style="color: #000000; font-weight: bold;">`</span></pre></td></tr></table></div>

<p>On check que les permissions ont bien été ajoutées :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">$ sudo getcap `which python`
/home/sam/.<span style="color: black;">local</span>/share/virtualenvs/super_projet/bin/python <span style="color: #66cc66;">=</span> cap_net_bind_service+eip</pre></td></tr></table></div>

<p>On a rajouté avec le <code>+</code> la permission <code>cap_net_bind_service</code> pour les cas <code>e</code> et <code>p</code> qui correspondent aux premières lettres de ces définitions :</p>
<pre>
Permitted (formerly known as forced):
    These capabilities are automatically permitted to the thread, regardless of the thread's inheritable capabilities. 

Inheritable (formerly known as allowed):
    This set is ANDed with the thread's inheritable set to determine which inheritable capabilities are enabled in the permitted set of the thread after the execve(2). 

Effective:
    This is not a set, but rather just a single bit. If this bit is set, then during an execve(2) all of the new permitted capabilities for the thread are also raised in the effective set. If this bit is not set, then after an execve(2), none of the new permitted capabilities is in the new effective set.
</pre>
<p>Et je n&#8217;ai absolument rien compris à celles-ci, je sais juste que ça marche.</p>
<p>Voilà, maintenant tout ce que vous lancez avec le Python de ce virtualenv peut se binder au port 80.</p>
<p>Si vous n&#8217;aimez pas l&#8217;idée de donner cette permission à tout un Python, il existe une alternative : rediriger tout ce qui rentre sur le port 80 vers un autre port. </p>
<p>Pour ça on peut utiliser un autre soft :</p>

<div class="wp_syntax"><table><tr><td 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 install</span> socat</pre></td></tr></table></div>

<p>Par exemple, balancer tout le trafic du port <code>80</code> vers le port <code>8080</code> :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="bash" style="font-family:monospace;">socat tcp-listen:<span style="color: #000000;">80</span>,fork,reuseaddr tcp:localhost:<span style="color: #000000;">8080</span></pre></td></tr></table></div>

<p>Et pouf, votre appli qui écoute sur le port <code>8080</code> reçoit le trafic du port <code>80</code>.</p>
<p>C&#8217;est plus simple, mais il faut le faire pour chaque port, et s&#8217;assurer que la commande est bien lancée au démarrage du serveur.</p>


feed_id: http://sametmax.com/?p=15829
title: Des pastes mystérieux sur 0bin 13
uri: Des-pastes-mystérieux-sur-0bin-3-Recently-updated
url: http://sametmax.com/des-pastes-mysterieux-sur-0bin/
content:
<p>J&#8217;ai reçu un email étrange nous signalant des pastes sur 0bin.net comme étant pédophiles et nous demandant de les retirer.</p>
<p>Le contenu en question ressemble à <a href="http://0bin.net/paste/pWslE1qOGn+GtbiY#PW8h9xgQdoTEdV1mT1+0koff3jSDrVQ7Yu7r2p2algM">ceci</a>. Vous pouvez cliquer, c&#8217;est safe.</p>
<p>Vu les abus de DMCA ces temps-ci, je suis plutôt méfiant sur ce genre d&#8217;allégation, et j&#8217;ai donc demandé un peu plus de détails. La personne, contrairement à pas mal de mecs de boites avec des avocats, a pris le temps de quelques échanges avec moi et, malgré mon ton clairement sceptique, a fini par m&#8217;expliquer le principe. </p>
<p>Certains forums hébergeant des photos sexualisant des mineurs sont accessibles au public. Néanmoins, pour y accéder, il faut obtenir des indices qui changent régulièrement. Ces indices sont postés sur des boards jetables, comme <a href="https://www.facebook.com/jakwejsc/app_190322544333196">cette page facebook</a>, qui pointe sur des pastebin, dans notre cas 0bin.</p>
<p>Ensuite, il faut aller sur le site connu pour son contenu, ajouter les filtres adblocks, faire quelques manipulations JS (dans l&#8217;exemple, un flag localstorage), et l&#8217;entrée est possible.</p>
<p>Je vire donc ces pastes quand on me les signale, et je fais circuler l&#8217;info, au cas où vous tombiez sur ce genre de trucs, que vous sachiez de quoi il retourne.</p>
<p>0bin n&#8217;étant pas modérable (c&#8217;est le principe), il est logique que des usages non souhaités en soit fait. J&#8217;aimerais donc profiter de cet article pour rappeler que le chiffrement n&#8217;est pas que pour les terroristes et les pédophiles. Tout comme les couteaux ne sont pas uniquement pour les serial killers : la plupart des gens découpent des carottes avec. </p>
<p>Il y a, en proportion, peu de pédophiles, et peu de serial killers. Ils existent, il ne faut pas les ignorer. Mais ne paniquons pas à l&#8217;idée qu&#8217;ils utilisent des outils utiles pour les citoyens lambda également. <strong>Nous créons un monde pour ces citoyens, pas pour les autres.</strong></p>


feed_id: http://sametmax.com/?p=15846
title: Le don du mois : Python requests 4
uri: Le-don-du-mois-Python-requests-2
url: http://sametmax.com/le-don-du-mois-python-requests/
content:
<p>Il n&#8217;y aucune cohérence dans ma manière de donner. Je le fais au fil de l&#8217;eau, anarchiquement. Parfois j&#8217;oublie pendant des mois et des mois.</p>
<p>Là, je me baladais sur l&#8217;<a href="http://docs.python-requests.org/en/latest/user/quickstart/">excellente documentation</a> de la non moins excellente lib requests, à la recherche du one-liner qui allait, encore une fois, me faire gagner un bon quart d&#8217;heure.</p>
<p>Et j&#8217;ai vu un bouton &#8220;Buy request pro&#8221;.</p>
<p>Curieux. Il y a plus mieux que le meilleur de requests ?</p>
<p>Je clique, et en fait le bouton est juste là pour proposer de supporter requests. On &#8220;achète&#8221; la lib gratuite :)</p>
<p>Le minimum est $12, ce qui est fort raisonnable considérant que ce petit bout de code m&#8217;a sauvé la mise un million de fois :</p>
<ul>
<li>Pas besoin de se soucier de l&#8217;encoding du payload.</li>
<li>Traitement élégant des headers.</li>
<li>Api super simple et propre.</li>
<li>Doc excellente.</li>
<li>Ergonomie mettant les cas les plus courants à portée de main.</li>
<li>Automatisation des choses importantes comme les redirections ou les cookies.</li>
<li>Fonctions avancées pour les cas compliqués comme la vérification SSL.</li>
<li>Extensibilité.</li>
<li>Un claque pédagogique qui a influencé toute la communauté Python.</li>
</ul>
<p>Bref, 10 euros, c&#8217;est le prix de mon amour en février. Je suis un mec facile.</p>


feed_id: http://sametmax.com/?p=15851
title: Recentrer les efforts dans l’open source 18
uri: Recentrer-les-efforts-dans-l-open-source-7-Recently-updated
url: http://sametmax.com/recentrer-les-efforts-dans-lopen-source/
content:
<p>Je râle souvent en ce moment contre les gens qui réinventent la roue. Dernièrement, c&#8217;était pour les gens qui sortaient chaque semaine une nouvelle lib pour accéder à un dico avec la syntaxe <code>dico.cle.cle.cle</code>.</p>
<p>Cela m&#8217;énerve doublement.</p>
<p>D&#8217;abord parce c&#8217;est de l&#8217;énergie perdue : le temps passé à développer cette nouvelle lib aurait pu être consacré à améliorer l&#8217;ancienne, la maintenir, la corriger, etc. C&#8217;est pas comme si on avait trop de bras dans le monde de l&#8217;open source.</p>
<p>Ensuite, parce que ça créé plein de confusion.</p>
<p>Dans un monde où il y a 40000 libs, l&#8217;utilisateur qui doit choisir ne sait que faire. Créer une énième solution lui ajoute un choix, qu&#8217;il doit évaluer. Ca divise aussi l&#8217;impact de la publicité qu&#8217;on peut faire à la ou les meilleurs solutions. Et on sait que faire connaître quelque chose est difficile.</p>
<p>Bref, réinventer la roue est un pur gachi.</p>
<p>Certes, pas pour l&#8217;auteur. Il a amélioré ses capacités techniques, il s&#8217;est peut être même amusé, et il a mis un coup de polish a son égo. Je le sais, moi aussi je le fais. J&#8217;aime ça.</p>
<p>Mais le monde du libre ne fonctionne que si on peut mettre son cul de côté de temps à autre. Déjà qu&#8217;on utilise gratos tout le boulot des autres, c&#8217;est le minimum de se sentir un peu concerné, non ?</p>
<p>Alors, évidement, je ne parle pas de recréer une lib pour le même usage, mais qui le fait différemment. Où alors un fork du fait de mésentente avec la direction précédente du projet. Il y a des raisons acceptables pour faire une autre roue.</p>
<p>Il y a néanmoins des cas évidents où ce n&#8217;est pas le cas.</p>
<p>Par exemple, j&#8217;avais pondu <a href="http://sametmax.com/twisted-et-requests/">requests-twisted</a> pour me faciliter la vie, n&#8217;ayant pas trouver quelque chose de similaire.</p>
<p>Ce matin, l&#8217;auteur de <a href="https://pypi.python.org/pypi/txrequests">txrequest</a> me <a href="https://github.com/sametmax/requests-twisted/issues/2">notifie</a> qu&#8217;il a lui aussi une lib qui fait pareil, mais un poil plus avancée, et me demande si je peux fermer mon projet et pointer vers le sien.</p>
<p>Je regarde son projet, je l&#8217;évalue. Effectivement, le sien est plus intéressant. Le mien n&#8217;apporte rien par rapport à lui. Et sa lib a clairement besoin de visibilité puisque je ne l&#8217;avais pas trouvée.</p>
<p>J&#8217;ai donc édité mon projet pour pointer vers son projet. Si j&#8217;ai des améliorations futures, je ferai un PR sur son repo.</p>
<p>La communauté, ce n&#8217;est pas 2 ou 3 gros exploits qui brillent. C&#8217;est la somme de milliers petites choses qui amène le mouvement dans la bonne direction.</p>


feed_id: http://sametmax.com/?p=15872
title: Un petit dashboard de monitoring avec Django et WAMP 1
uri: Un-petit-dashboard-de-monitoring-avec-Django-et-WAMP-Recently-updat
url: http://sametmax.com/un-petit-dashboard-de-monitoring-avec-django-et-wamp/
content:
<p><em>Cet article est écrit dans le cadre de ma <a href="http://sametmax.com/full-disclosure/">collaboration</a> avec Tavendo.</em></p>
<p>On a déjà vu que <a href="http://sametmax.com/crossbar-le-futur-des-applications-web-python/">WAMP c&#8217;est cool</a>, mais c&#8217;est asynchrone et nos frameworks Web chéris WSGI <a href="http://sametmax.com/wamp-et-les-outils-de-dev-web-python-existants/">sont synchrones</a>.</p>
<p>J&#8217;ai donné une solution de contournement avec la lib <a href="http://sametmax.com/les-managers-le-detestent-faites-tourner-wamp-dans-django-avec-cette-astuce-insolite/">crochet</a> qui permet de faire tourner du twisted de manière synchrone dans son projet.</p>
<p>Néanmoins, beaucoup sont, j&#8217;en suis certain, à la recherche d&#8217;un truc plus simple. En effet, le bénéfice le plus immédiat de WAMP sont les notifications en temps réel. Et pour ça, crossbar vient avec le <a href="https://github.com/crossbario/crossbar/wiki/HTTP%20Pusher%20Service">HTTP PUSHER service</a> : quelques lignes de JSON dans le fichier de config de crossbar et zou, on peut publier sur un topic WAMP avec une simple requête POST :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="javascript" style="font-family:monospace;"> <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;notify&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;pusher&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;role&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;anonymous&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></pre></td></tr></table></div>

<p>Et derrière, pour publier un event sur le sujet &#8220;super_sujet&#8221;, on peut faire :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> requets
requests.<span style="color: black;">post</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;http://ip_du_router/pusher&quot;</span><span style="color: #66cc66;">,</span>
                  json<span style="color: #66cc66;">=</span><span style="color: black;">&#123;</span>
                      <span style="color: #483d8b;">'topic'</span>: <span style="color: #483d8b;">'super_sujet'</span>
                      <span style="color: #483d8b;">'args'</span>: <span style="color: black;">&#91;</span>queques<span style="color: #66cc66;">,</span> params<span style="color: #66cc66;">,</span> a<span style="color: #66cc66;">,</span> passer<span style="color: #66cc66;">,</span> si<span style="color: #66cc66;">,</span> on veut<span style="color: black;">&#93;</span>
                  <span style="color: black;">&#125;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Ceci va envoyer une requête POST à un service de crossbar qui va transformer ça en véritable publish WAMP.</p>
<p>Histoire d&#8217;illustrer tout ça, je vais vous montrer comment construire un petit service de monitoring avec Crossbar.io et Django. Pour suivre le tuto vous aurez besoin :</p>
<ul>
<li>De connaissances de base en JS.</li>
<li>De connaître le principe de WAMP.</li>
<li>De savoir installer des bibliothèques Python avec extensions sur votre machine. <a href="https://duckduckgo.com/l/?kh=-1&#038;uddg=http%3A%2F%2Fsametmax.com%2Fvotre-python-aime-les-pip%2F">pip</a> et <a href="http://sametmax.com/les-environnement-virtuels-python-virtualenv-et-virtualenvwrapper">virtualenv</a> sont vos amis.</li>
<li>De connaître Django. Même si le concept peut s&#8217;appliquer à Flask, Pyramid, ou autre.</li>
</ul>
<p><span class='embed-youtube' style='text-align:center; display: block;'><iframe class='youtube-player' type='text/html' width='1170' height='689' src='http://www.youtube.com/embed/e9Xtl22x5Sg?version=3&#038;rel=1&#038;fs=1&#038;showsearch=0&#038;showinfo=1&#038;iv_load_policy=1&#038;wmode=transparent' frameborder='0' allowfullscreen='true'></iframe></span></p>
<h2>Premiers pas</h2>
<p>Le but du jeu est d&#8217;avoir un petit client WAMP qu&#8217;on lance sur chaque machine qu&#8217;on veut monitorer. Celui-ci va, toutes les x secondes, récupérer l&#8217;usage CPU, RAM et disque et faire un publish WAMP.</p>
<div id="attachment_15876" style="width: 600px" class="wp-caption aligncenter"><a href="media/df4be958.architecture.png" data-original-source="http://sametmax.com/wp-content/uploads/2015/02/architecture.png" class="grouped_elements" rel="tc-fancybox-group15872"><img src="media/df4be958.architecture.png" data-original-source="http://sametmax.com/wp-content/uploads/2015/02/architecture.png" alt="Chaque machine possède un client WAMP" width="590" height="654" class="size-full wp-image-15876" /></a><p class="wp-caption-text">Chaque machine possède un client WAMP</p></div>
<p>A l&#8217;autre bout, on a un site Django qui a un modèle pour chaque machine monitorée, avec des valeurs pour dire si on est intéressé par le CPU, la RAM ou le disque et la valeur de x.</p>
<p>Une page affiche en temps réel tous les relevés pour toutes les machines. Si dans l&#8217;admin de Django on change un modèle, la page reflète ce changement.</p>
<div id="attachment_15877" style="width: 710px" class="wp-caption aligncenter"><a href="media/b7790b85.dashboard.gif" data-original-source="http://sametmax.com/wp-content/uploads/2015/02/dashboard.gif" class="grouped_elements" rel="tc-fancybox-group15872"><img src="media/b7790b85.dashboard.gif" data-original-source="http://sametmax.com/wp-content/uploads/2015/02/dashboard.gif" alt="Si je déclique &quot;CPU&quot; dans l&#039;admin Django, les CPUs ne sont plus affichés" width="700" height="650" class="size-full wp-image-15877" /></a><p class="wp-caption-text">Si je déclique &#8220;CPU&#8221; dans l&#8217;admin Django, les CPUs ne sont plus affichés</p></div>
<p> On aura donc besoin de django (<code>pip install Django</code>, ça c&#8217;est pas trop dur), requests (<code>pip install requests</code>, jusqu&#8217;ici tout va bien), et <a href="pythonhosted.org/psutil/">psutil</a>.</p>
<p>psutil est la lib Python qui va nous permettre de récupérer toutes le valeurs pour la RAM, le disque et le CPU. Elle utilise des extensions en C, il faut donc un compilateur et les headers Python. Sous Ubuntu, il faut donc faire :</p>

<div class="wp_syntax"><table><tr><td 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 install</span> <span style="color: #c20cb9; font-weight: bold;">gcc</span> python-dev</pre></td></tr></table></div>

<p>Sous CentOS ça donne :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">yum groupinstall</span> <span style="color: #ff0000;">&quot;Development tools&quot;</span>
<span style="color: #c20cb9; font-weight: bold;">yum install</span> python-devel</pre></td></tr></table></div>

<p>Sous Mac, les headers Python devraient être inclus, mais il vous faut aussi GCC. Si vous avez xcode, vous avez déjà un compilateur, sinon, il existe un installeur <a href="https://github.com/kennethreitz/osx-gcc-installer#readme">plus léger</a>.</p>
<p>Sous windows, c&#8217;est un wheel donc rien à faire normalement.</p>
<p>Et reste plus qu&#8217;à <code>pip install psutil</code>.</p>
<p>Enfin il nous faudra, logique, <a href="http://crossbar.io/docs/Local-Installation/">installer crossbar</a>. <code>pip install crossbar</code>, sachant que <a href="http://crossbar.io/docs/Installation-on-Windows/">sous Windows</a> vous aurez besoin de <a href="http://sourceforge.net/projects/pywin32/files/pywin32/Build%20219/">PyWin32</a> et comme toujours, d&#8217;avoir les dossiers <code>C:\Python27\</code> and <code>C:\Python27\Scripts</code> dans votre <a href="http://sametmax.com/ajouter-un-chemin-a-la-variable-denvironnement-path-sous-windows/">PATH</a>.</p>
<h2>Le HTML</h2>
<p>On a besoin que d&#8217;une page. Afin de rendre le tuto agnostique, je l&#8217;ai fait en pur JS, pas de jQuery, pas d&#8217;Angular. Donc c&#8217;est verbeux :)</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="html" style="font-family:monospace;">&lt;!DOCTYPE html&gt;
&lt;html&gt;
  &lt;head&gt;
    &lt;meta charset=&quot;utf-8&quot; /&gt;
&nbsp;
    &lt;!-- De quoi cacher un bloc facilement --&gt;
    &lt;style type=&quot;text/css&quot;&gt;
        .hide {display:none;}
    &lt;/style&gt;
&nbsp;
    &lt;!--
        La lib JS qui permet de parler WAMP .
&nbsp;
        Ici je suppose qu'on utilise un navigateur qui support websocket.
        Il est possible de faire du fallback sur flash ou long poll, mais
        ce sont des dépendances en plus.
    --&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;
&nbsp;
&nbsp;
    &lt;!-- Tout notre code client, inline pour faciliter votre lecture --&gt;
    &lt;script type=&quot;text/javascript&quot;&gt;
&nbsp;
      /* Connexion à notre serveur WAMP */
      window.addEventListener(&quot;load&quot;, function(){
        var connection = new autobahn.Connection({
           url: 'ws://127.0.0.1:8080/ws',
           realm: 'realm1'
        });
&nbsp;
        /* Quand la connexion est ouverte, exécuter ce code */
        connection.onopen = function(session) {
&nbsp;
          var clients = document.getElementById(&quot;clients&quot;);
&nbsp;
          /* Quand on reçoit l'événement clientstats, lancer cette fonction */
          session.subscribe('clientstats', function(args){
            var stats = args[0];
            var serverNode = document.getElementById(stats.ip);
&nbsp;
            /*
                 Créer un li contenant un h2 et un dl pour ce client si
                 il n'est pas encore dans la page.
            */
            if (!serverNode){
                serverNode = document.createElement(&quot;li&quot;);
                serverNode.id = stats.ip;
                serverNode.appendChild(document.createElement(&quot;h2&quot;));
                serverNode.appendChild(document.createElement(&quot;dl&quot;));
                serverNode.firstChild.innerHTML = stats.name + &quot; (&quot; + stats.ip + &quot;)&quot;;
                clients.appendChild(serverNode);
&nbsp;
                // Cacher les infos du serveur si il est désactivé.
                session.subscribe('clientconfig.' + stats.ip, function(args){
                    var config = args[0];
                    if (config.disabled){
                        var serverNode = document.getElementById(config.ip);
                        serverNode.className = &quot;hide&quot;;
                    }
                });
&nbsp;
            }
&nbsp;
            // Remettre à zéro le contenu du li du serveur.
            serverNode.className = &quot;&quot;;
            var dl = serverNode.lastChild;
            while (dl.hasChildNodes()) {
                dl.removeChild(dl.lastChild);
            }
&nbsp;
            // Si on a des infos sur le CPU, les afficher
            if (stats.cpus){
                var cpus = document.createElement(&quot;dt&quot;);
                cpus.innerHTML = &quot;CPUs:&quot;;
                dl.appendChild(cpus);
                for (var i = 0; i &lt; stats.cpus.length; i++) {
                    var cpu = document.createElement(&quot;dd&quot;);
                    cpu.innerHTML = stats.cpus[i];
                    dl.appendChild(cpu);
                };
            }
&nbsp;
            // Si on a des infos sur l'espace disque, les afficher
            if (stats.disks){
                var disks = document.createElement(&quot;dt&quot;);
                disks.innerHTML = &quot;Disk usage:&quot;;
                dl.appendChild(disks);
                for (key in stats.disks) {
                    var disk = document.createElement(&quot;dd&quot;);
                    disk.innerHTML = &quot;&lt;strong&gt;&quot; + key + &quot;&lt;/strong&gt;: &quot; + stats.disks[key];
                    dl.appendChild(disk);
                };
            }
&nbsp;
            // Si on a des infos sur l'usage mémoire, les afficher.
            if (stats.memory){
                var memory = document.createElement(&quot;dt&quot;);
                memory.innerHTML = &quot;Memory:&quot;;
                dl.appendChild(memory);
                var memVal = document.createElement(&quot;dd&quot;);
                memVal.innerHTML = stats.memory;
                dl.appendChild(memVal);
            }
&nbsp;
          });
&nbsp;
        };
&nbsp;
        // Ouvrir la connexion avec le routeur WAMP.
        connection.open();
&nbsp;
      });
    &lt;/script&gt;
&nbsp;
    &lt;title&gt; Monitoring&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;h1&gt; Monitoring &lt;/h1&gt;
    &lt;ul id=&quot;clients&quot;&gt;&lt;/ul&gt;
&lt;/body&gt;
&nbsp;
&lt;/html&gt;</pre></td></tr></table></div>

<p>Comme vous pouvez le voir, c&#8217;est beaucoup de JS ordinaire et du DOM. Les seules parties spécifiques à WAMP sont :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #000066; font-weight: bold;">var</span> connection <span style="color: #339933;">=</span> <span style="color: #000066; 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://127.0.0.1:8080/ws'</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>
connection.<span style="color: #660066;">onopen</span> <span style="color: #339933;">=</span> <span style="color: #000066; 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: #009900;">&#125;</span>
connection.<span style="color: #660066;">open</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

<p>Pour se connecter au serveur.</p>
<p>Et :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="javascript" style="font-family:monospace;">session.<span style="color: #660066;">subscribe</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'nom_du_sujet'</span><span style="color: #339933;">,</span> <span style="color: #000066; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>args<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
...
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>Pour réagir à la publication d&#8217;un sujet WAMP.</p>
<h2>Le client de monitoring</h2>
<p>C&#8217;est la partie qui va aller sur chaque machine qu&#8217;on veut surveiller.</p>

<div class="wp_syntax"><table><tr><td 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> <span style="color: #dc143c;">__future__</span> <span style="color: #ff7700;font-weight:bold;">import</span> division
&nbsp;
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">socket</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">import</span> requests
<span style="color: #ff7700;font-weight:bold;">import</span> psutil
&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
<span style="color: #ff7700;font-weight:bold;">from</span> autobahn.<span style="color: black;">twisted</span>.<span style="color: black;">util</span> <span style="color: #ff7700;font-weight:bold;">import</span> sleep
&nbsp;
<span style="color: #ff7700;font-weight:bold;">from</span> twisted.<span style="color: black;">internet</span>.<span style="color: black;">defer</span> <span style="color: #ff7700;font-weight:bold;">import</span> inlineCallbacks
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> to_gib<span style="color: black;">&#40;</span><span style="color: #dc143c;">bytes</span><span style="color: #66cc66;">,</span> factor<span style="color: #66cc66;">=</span><span style="color: #ff4500;">2</span>**<span style="color: #ff4500;">30</span><span style="color: #66cc66;">,</span> suffix<span style="color: #66cc66;">=</span><span style="color: #483d8b;">&quot;GiB&quot;</span><span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot; Converti un nombre d'octets en gibioctets.
&nbsp;
        Ex : 1073741824 octets = 1073741824/2**30 = 1GiO
    &quot;&quot;&quot;</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #483d8b;">&quot;%0.2f%s&quot;</span> % <span style="color: black;">&#40;</span><span style="color: #dc143c;">bytes</span> / factor<span style="color: #66cc66;">,</span> suffix<span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> get_infos<span style="color: black;">&#40;</span>filters<span style="color: #66cc66;">=</span><span style="color: black;">&#123;</span><span style="color: black;">&#125;</span><span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot; Retourne la valeur actuelle de l'usage CPU, mémoire et disque.
&nbsp;
        Ces valeurs sont retournées sous la forme d'un dictionnaire :
&nbsp;
            {
                'cpus': ['x%', 'y%', etc],
                'memory': &quot;z%&quot;,
                'disk':{
                    '/partition/1': 'x/y (z%)',
                    '/partition/2': 'x/y (z%)',
                    etc
                }
            }
&nbsp;
        Le paramètre filter est un dico de la forme :
&nbsp;
            {'cpus': bool, 'memory':bool, 'disk':bool}
&nbsp;
        Il est utilisé pour décider d'inclure ou non les résultats des mesures
        pour les 3 types de ressource.
&nbsp;
    &quot;&quot;&quot;</span>
&nbsp;
    results <span style="color: #66cc66;">=</span> <span style="color: black;">&#123;</span><span style="color: black;">&#125;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: black;">&#40;</span>filters.<span style="color: black;">get</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'show_cpus'</span><span style="color: #66cc66;">,</span> <span style="color: #008000;">True</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>:
        results<span style="color: black;">&#91;</span><span style="color: #483d8b;">'cpus'</span><span style="color: black;">&#93;</span> <span style="color: #66cc66;">=</span> <span style="color: #008000;">tuple</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;%s%%&quot;</span> % x <span style="color: #ff7700;font-weight:bold;">for</span> x <span style="color: #ff7700;font-weight:bold;">in</span> psutil.<span style="color: black;">cpu_percent</span><span style="color: black;">&#40;</span>percpu<span style="color: #66cc66;">=</span><span style="color: #008000;">True</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: black;">&#40;</span>filters.<span style="color: black;">get</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'show_memory'</span><span style="color: #66cc66;">,</span> <span style="color: #008000;">True</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>:
        memory <span style="color: #66cc66;">=</span> psutil.<span style="color: black;">phymem_usage</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        results<span style="color: black;">&#91;</span><span style="color: #483d8b;">'memory'</span><span style="color: black;">&#93;</span> <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">'{used}/{total} ({percent}%)'</span>.<span style="color: black;">format</span><span style="color: black;">&#40;</span>
            used<span style="color: #66cc66;">=</span>to_gib<span style="color: black;">&#40;</span>memory.<span style="color: black;">active</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span>
            total<span style="color: #66cc66;">=</span>to_gib<span style="color: black;">&#40;</span>memory.<span style="color: black;">total</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span>
            percent<span style="color: #66cc66;">=</span>memory.<span style="color: black;">percent</span>
        <span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: black;">&#40;</span>filters.<span style="color: black;">get</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'show_disk'</span><span style="color: #66cc66;">,</span> <span style="color: #008000;">True</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>:
        disks <span style="color: #66cc66;">=</span> <span style="color: black;">&#123;</span><span style="color: black;">&#125;</span>
        <span style="color: #ff7700;font-weight:bold;">for</span> device <span style="color: #ff7700;font-weight:bold;">in</span> psutil.<span style="color: black;">disk_partitions</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
            usage <span style="color: #66cc66;">=</span> psutil.<span style="color: black;">disk_usage</span><span style="color: black;">&#40;</span>device.<span style="color: black;">mountpoint</span><span style="color: black;">&#41;</span>
            disks<span style="color: black;">&#91;</span>device.<span style="color: black;">mountpoint</span><span style="color: black;">&#93;</span> <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">'{used}/{total} ({percent}%)'</span>.<span style="color: black;">format</span><span style="color: black;">&#40;</span>
                used<span style="color: #66cc66;">=</span>to_gib<span style="color: black;">&#40;</span>usage.<span style="color: black;">used</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span>
                total<span style="color: #66cc66;">=</span>to_gib<span style="color: black;">&#40;</span>usage.<span style="color: black;">total</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span>
                percent<span style="color: #66cc66;">=</span>usage.<span style="color: black;">percent</span>
            <span style="color: black;">&#41;</span>
        results<span style="color: black;">&#91;</span><span style="color: #483d8b;">'disks'</span><span style="color: black;">&#93;</span> <span style="color: #66cc66;">=</span> disks
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">return</span> results
&nbsp;
<span style="color: #808080; font-style: italic;"># On créé le client WAMP.</span>
app <span style="color: #66cc66;">=</span> Application<span style="color: black;">&#40;</span><span style="color: #483d8b;">'monitoring'</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Ceci est l'IP publique de ma machine puisque</span>
<span style="color: #808080; font-style: italic;"># ce client doit pouvoir accéder à mon serveur</span>
<span style="color: #808080; font-style: italic;"># depuis l'extérieur.</span>
SERVER <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">'172.17.42.1'</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># D'abord on utilise une astuce pour connaître l'IP publique de cette</span>
<span style="color: #808080; font-style: italic;"># machine.</span>
s <span style="color: #66cc66;">=</span> <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: #66cc66;">,</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: #66cc66;">,</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 attache un dictionnaire à l'app, ainsi</span>
<span style="color: #808080; font-style: italic;"># sa référence sera accessible partout.</span>
app._params <span style="color: #66cc66;">=</span> <span style="color: black;">&#123;</span><span style="color: #483d8b;">'name'</span>: <span style="color: #dc143c;">socket</span>.<span style="color: black;">gethostname</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'ip'</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><span style="color: black;">&#125;</span>
s.<span style="color: black;">close</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #66cc66;">@</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: #66cc66;">@</span>inlineCallbacks
<span style="color: #ff7700;font-weight:bold;">def</span> called_on_joinded<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot; Boucle envoyant l'état de cette machine avec WAMP toutes les x secondes.
&nbsp;
        Cette fonction est exécutée quand le client &quot;joins&quot; le router, c'est
        à dire qu'il est connecté et authentifié, prêt à envoyer des messages
        WAMP.
    &quot;&quot;&quot;</span>
    <span style="color: #808080; font-style: italic;"># Ensuite on fait une requête post au serveur pour dire qu'on est</span>
    <span style="color: #808080; font-style: italic;"># actif et récupérer les valeurs de configuration de notre client.</span>
    app._params.<span style="color: black;">update</span><span style="color: black;">&#40;</span>requests.<span style="color: black;">post</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'http://'</span> + SERVER + <span style="color: #483d8b;">':8080/clients/'</span><span style="color: #66cc66;">,</span>
                                    data<span style="color: #66cc66;">=</span><span style="color: black;">&#123;</span><span style="color: #483d8b;">'ip'</span>: app._params<span style="color: black;">&#91;</span><span style="color: #483d8b;">'ip'</span><span style="color: black;">&#93;</span><span style="color: black;">&#125;</span><span style="color: black;">&#41;</span>.<span style="color: black;">json</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
&nbsp;
    <span style="color: #808080; font-style: italic;"># Puis on boucle indéfiniment</span>
    <span style="color: #ff7700;font-weight:bold;">while</span> <span style="color: #008000;">True</span>:
        <span style="color: #808080; font-style: italic;"># Chaque tour de boucle, on récupère les infos de notre machine</span>
        infos <span style="color: #66cc66;">=</span> <span style="color: black;">&#123;</span><span style="color: #483d8b;">'ip'</span>: app._params<span style="color: black;">&#91;</span><span style="color: #483d8b;">'ip'</span><span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'name'</span>: app._params<span style="color: black;">&#91;</span><span style="color: #483d8b;">'name'</span><span style="color: black;">&#93;</span><span style="color: black;">&#125;</span>
        infos.<span style="color: black;">update</span><span style="color: black;">&#40;</span>get_infos<span style="color: black;">&#40;</span>app._params<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
        <span style="color: #808080; font-style: italic;"># Si les stats sont a envoyer, on fait une publication WAMP.</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> app._params<span style="color: black;">&#91;</span><span style="color: #483d8b;">'disabled'</span><span style="color: black;">&#93;</span>:
            app.<span style="color: black;">session</span>.<span style="color: black;">publish</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'clientstats'</span><span style="color: #66cc66;">,</span> infos<span style="color: black;">&#41;</span>
&nbsp;
        <span style="color: #808080; font-style: italic;"># Et on attend. Grâce à @inlineCallbacks, utiliser yield indique</span>
        <span style="color: #808080; font-style: italic;"># qu'on ne bloque pas ici, donc pendant ce temps notre client</span>
        <span style="color: #808080; font-style: italic;"># peut écouter les événements WAMP et y réagir.</span>
        <span style="color: #ff7700;font-weight:bold;">yield</span> sleep<span style="color: black;">&#40;</span>app._params<span style="color: black;">&#91;</span><span style="color: #483d8b;">'frequency'</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
&nbsp;
&nbsp;
<span style="color: #808080; font-style: italic;"># On dit qu'on est intéressé par les événements concernant clientconfig</span>
<span style="color: #66cc66;">@</span>app.<span style="color: black;">subscribe</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'clientconfig.'</span> + app._params<span style="color: black;">&#91;</span><span style="color: #483d8b;">'ip'</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> update_configuration<span style="color: black;">&#40;</span>args<span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot; Met à jour la configuration du client quand Django nous le demande. &quot;&quot;&quot;</span>
    app._params.<span style="color: black;">update</span><span style="color: black;">&#40;</span>args<span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># On démarre notre client.</span>
<span style="color: #ff7700;font-weight:bold;">if</span> __name__ <span style="color: #66cc66;">==</span> <span style="color: #483d8b;">'__main__'</span>:
    app.<span style="color: black;">run</span><span style="color: black;">&#40;</span>url<span style="color: #66cc66;">=</span><span style="color: #483d8b;">&quot;ws://%s:8080/ws&quot;</span> % SERVER<span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Le plus gros du code est <code>get_infos()</code> qui n&#8217;a rien à voir avec WAMP. C&#8217;est nous, manipulant <code>psutil</code> pour obtenir les relevés de cette machine. Je ne recommande bien évidement pas de faire ça en prod : une grosse fonction monolithique qui prend un dico en param. Mais c&#8217;est pour une démo, et ça me permet de grouper les instructions qui vont ensemble pour faciliter votre compréhension.</p>
<p>La partie qui concerne WAMP :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">app <span style="color: #66cc66;">=</span> Application<span style="color: black;">&#40;</span><span style="color: #483d8b;">'monitoring'</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #66cc66;">@</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: #66cc66;">@</span>inlineCallbacks
<span style="color: #ff7700;font-weight:bold;">def</span> called_on_joinded<span style="color: black;">&#40;</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: black;">app</span>.<span style="color: black;">session</span>.<span style="color: black;">publish</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'clientstats'</span><span style="color: #66cc66;">,</span> infos<span style="color: black;">&#41;</span>
        ...
        <span style="color: #ff7700;font-weight:bold;">yield</span> sleep<span style="color: black;">&#40;</span>app._params<span style="color: black;">&#91;</span><span style="color: #483d8b;">'frequency'</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p><code>app = Application('monitoring')</code> créé un client WAMP, et <code>@app.signal('onjoined')</code> nous dit de lancer la fonction quand notre client est connecté et prêt à envoyer des événements. <code>@inlineCallbacks</code> est une spécificité de Twisted qui nous permet d&#8217;écrire du code asynchrone sans avoir à mettre des callback partout : à la place on met des <code>yield.</code></p>
<p>Tout le boulot de notre client a lieu dans la boucle : <code>app.session.publish('clientstats', infos)</code> publie les nouvelles mesures de CPU/RAM/Disque via WAMP, puis attend un certain temps (<code>yield sleep(app._params['frequency'])</code>) avant de le faire à nouveau. L&#8217;attente n&#8217;est pas bloquante car elle se fait avec le <code>sleep</code> de Twisted.</p>
<p>N&#8217;oublions pas :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">@</span>app.<span style="color: black;">subscribe</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'clientconfig.'</span> + app._params<span style="color: black;">&#91;</span><span style="color: #483d8b;">'ip'</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> update_configuration<span style="color: black;">&#40;</span>args<span style="color: black;">&#41;</span>:
    app._params.<span style="color: black;">update</span><span style="color: black;">&#40;</span>args<span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>La fonction <code>update_configuration()</code> sera appelée à chaque fois qu&#8217;une publication WAMP sera faite sur le sujet <code>clientconfig.&lt;ip_du_client&gt;</code>. Notre fonction ne fait que mettre à jour la configuration du client, qui est un dico de la forme :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">    <span style="color: black;">&#123;</span><span style="color: #483d8b;">'cpus'</span>: <span style="color: #008000;">True</span><span style="color: #66cc66;">,</span>
    <span style="color: #483d8b;">'memory'</span>: <span style="color: #008000;">False</span><span style="color: #66cc66;">,</span>
    <span style="color: #483d8b;">'disk'</span>: <span style="color: #008000;">True</span><span style="color: #66cc66;">,</span>
    <span style="color: #483d8b;">'disabled'</span>: <span style="color: #008000;">False</span><span style="color: #66cc66;">,</span>
    <span style="color: #483d8b;">'frequency'</span>: <span style="color: #ff4500;">1</span><span style="color: black;">&#125;</span></pre></td></tr></table></div>

<p>C&#8217;est ce dico qui est utilisé par <code>get_infos()</code> pour choisir quelles mesures récupérer, et aussi par <code>sleep()</code> pour savoir combien de secondes attendre avant la prochaine mesure.</p>
<p>La valeur initiale de ce dico est récupérée au lancement du client, en faisant :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">app._params.<span style="color: black;">update</span><span style="color: black;">&#40;</span>requests.<span style="color: black;">post</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'http://'</span> + SERVER + <span style="color: #483d8b;">':8080/clients/'</span><span style="color: #66cc66;">,</span>
                                    data<span style="color: #66cc66;">=</span><span style="color: black;">&#123;</span><span style="color: #483d8b;">'ip'</span>: app._params<span style="color: black;">&#91;</span><span style="color: #483d8b;">'ip'</span><span style="color: black;">&#93;</span><span style="color: black;">&#125;</span><span style="color: black;">&#41;</span>.<span style="color: black;">json</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p><code>requests.post(url_du_serveur, data={'ip': app._params['ip']}).json()</code> fait en effet une requête POST vers une URL de django qui nous allons voir plus loin, et qui retourne la configuration du client portant cette IP sous forme de JSON.</p>
<p>On utilise donc une fois HTTP pour obtenir les valeurs de départs, et ensuite WAMP pour les mises à jours des futures valeurs. WAMP et HTTP ne s&#8217;excluent pas : ils sont complémentaires.</p>
<p>Petite parenthèse sur :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">SERVER <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">'172.17.42.1'</span>
&nbsp;
s <span style="color: #66cc66;">=</span> <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: #66cc66;">,</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: #66cc66;">,</span> <span style="color: #ff4500;">80</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
app._params <span style="color: #66cc66;">=</span> <span style="color: black;">&#123;</span><span style="color: #483d8b;">'name'</span>: <span style="color: #dc143c;">socket</span>.<span style="color: black;">gethostname</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'ip'</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><span style="color: black;">&#125;</span>
s.<span style="color: black;">close</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>D&#8217;une part, j&#8217;ai mis l&#8217;IP du serveur qui va contenir Crossbar.io et Django en dur car je suis, je pense que maintenant vous le savez, une grosse feignasse. Mais en prod, vous me faites un paramètre, on est d&#8217;accord ? Ensuite, il faut que j&#8217;identifie mon client, ce que je fais avec l&#8217;adresse IP. Il me faut donc son adresse IP externe, et je l&#8217;obtiens avec une astuce consistant à me connecter à l&#8217;IP 8.8.8.8 (les DNS google \o/) et en fermant la connexion juste derrière. Ce me permet de voir comment les autres machines me voit depuis l’extérieur.</p>
<h2>Le site Django</h2>
<p>Puisque le prérequis de l&#8217;article et de connaître Django, ça va pas être trop dur.</p>
<p>On créé son projet et son app :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="bash" style="font-family:monospace;">django-admin startproject django_project
.<span style="color: #000000; font-weight: bold;">/</span>manage.py startapp django_app</pre></td></tr></table></div>

<p>On se rajoute un petit modèle qui contient la configuration de chaque client (vous vous souvenez, le fameux dico) :</p>

<div class="wp_syntax"><table><tr><td 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> requests
&nbsp;
<span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">db</span> <span style="color: #ff7700;font-weight:bold;">import</span> models
<span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">db</span>.<span style="color: black;">models</span>.<span style="color: black;">signals</span> <span style="color: #ff7700;font-weight:bold;">import</span> post_save
<span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">dispatch</span> <span style="color: #ff7700;font-weight:bold;">import</span> receiver
<span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">forms</span>.<span style="color: black;">models</span> <span style="color: #ff7700;font-weight:bold;">import</span> model_to_dict
&nbsp;
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> Client<span style="color: black;">&#40;</span>models.<span style="color: black;">Model</span><span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot; Configuration de notre client. &quot;&quot;&quot;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Pour l'identifier.</span>
    ip <span style="color: #66cc66;">=</span> models.<span style="color: black;">GenericIPAddressField</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Quelles données envoyer à notre dashboard</span>
    show_cpus <span style="color: #66cc66;">=</span> models.<span style="color: black;">BooleanField</span><span style="color: black;">&#40;</span>default<span style="color: #66cc66;">=</span><span style="color: #008000;">True</span><span style="color: black;">&#41;</span>
    show_memory <span style="color: #66cc66;">=</span> models.<span style="color: black;">BooleanField</span><span style="color: black;">&#40;</span>default<span style="color: #66cc66;">=</span><span style="color: #008000;">True</span><span style="color: black;">&#41;</span>
    show_disk <span style="color: #66cc66;">=</span> models.<span style="color: black;">BooleanField</span><span style="color: black;">&#40;</span>default<span style="color: #66cc66;">=</span><span style="color: #008000;">True</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Arrêter d'envoyer les données</span>
    disabled <span style="color: #66cc66;">=</span> models.<span style="color: black;">BooleanField</span><span style="color: black;">&#40;</span>default<span style="color: #66cc66;">=</span><span style="color: #008000;">False</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Fréquence de rafraîchissement des données</span>
    frequency <span style="color: #66cc66;">=</span> models.<span style="color: black;">IntegerField</span><span style="color: black;">&#40;</span>default<span style="color: #66cc66;">=</span><span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__unicode__</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;">self</span>.<span style="color: black;">ip</span>
&nbsp;
&nbsp;
<span style="color: #66cc66;">@</span>receiver<span style="color: black;">&#40;</span>post_save<span style="color: #66cc66;">,</span> sender<span style="color: #66cc66;">=</span>Client<span style="color: #66cc66;">,</span> dispatch_uid<span style="color: #66cc66;">=</span><span style="color: #483d8b;">&quot;server_post_save&quot;</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> notify_server_config_changed<span style="color: black;">&#40;</span>sender<span style="color: #66cc66;">,</span> instance<span style="color: #66cc66;">,</span> **kwargs<span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot; Notifie un client que sa configuration a changé.
&nbsp;
        Cette fonction est lancée quand on sauvegarde un modèle Client,
        et fait une requête POST sur le bridge WAMP-HTTP, nous permettant
        de faire un publish depuis Django.
    &quot;&quot;&quot;</span>
    requests.<span style="color: black;">post</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;http://127.0.0.1:8080/notify&quot;</span><span style="color: #66cc66;">,</span>
                  json<span style="color: #66cc66;">=</span><span style="color: black;">&#123;</span>
                      <span style="color: #483d8b;">'topic'</span>: <span style="color: #483d8b;">'clientconfig.'</span> + instance.<span style="color: black;">ip</span><span style="color: #66cc66;">,</span>
                      <span style="color: #483d8b;">'args'</span>: <span style="color: black;">&#91;</span>model_to_dict<span style="color: black;">&#40;</span>instance<span style="color: black;">&#41;</span><span style="color: black;">&#93;</span>
                  <span style="color: black;">&#125;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>La partie modèle est connue. L&#8217;astuce est dans :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">@</span>receiver<span style="color: black;">&#40;</span>post_save<span style="color: #66cc66;">,</span> sender<span style="color: #66cc66;">=</span>Client<span style="color: #66cc66;">,</span> dispatch_uid<span style="color: #66cc66;">=</span><span style="color: #483d8b;">&quot;server_post_save&quot;</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> notify_server_config_changed<span style="color: black;">&#40;</span>sender<span style="color: #66cc66;">,</span> instance<span style="color: #66cc66;">,</span> **kwargs<span style="color: black;">&#41;</span>:
    requests.<span style="color: black;">post</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;http://127.0.0.1:8080/notify&quot;</span><span style="color: #66cc66;">,</span>
                  json<span style="color: #66cc66;">=</span><span style="color: black;">&#123;</span>
                      <span style="color: #483d8b;">'topic'</span>: <span style="color: #483d8b;">'clientconfig.'</span> + instance.<span style="color: black;">ip</span><span style="color: #66cc66;">,</span>
                      <span style="color: #483d8b;">'args'</span>: <span style="color: black;">&#91;</span>model_to_dict<span style="color: black;">&#40;</span>instance<span style="color: black;">&#41;</span><span style="color: black;">&#93;</span>
                  <span style="color: black;">&#125;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>On utilise ici les signaux Django, une fonctionnalité du framework qui nous permet de lancer une fonction quand quelque chose se passe. Ici on dit &#8220;lance cette fonction quand le modèle <code>Client</code> est modifié&#8221;.</p>
<p>Donc <code>notify_server_config_changed</code> va se lancer quand la config d&#8217;un client est modifiée, par exemple dans l&#8217;admin, et recevoir l&#8217;objet modifié via son paramètre <code>instance</code>.</p>
<p>On fait alors une petite requête POST sur <code>http://127.0.0.1:8080/notify</code>, l&#8217;URL sur laquelle on configurera plus loin notre service de push. En faisant une requête dessus, on va demander à Crossbar.io de transformer la requête HTTP en message publish WAMP, ici sur le sujet &#8216;clientconfig.&lt;ip_du_client&gt;&#8217;. On publie donc un message WAMP, depuis Django.</p>
<p>Ca marche depuis n&#8217;importe où, pas juste Django. Depuis le shell, depuis Flask, n&#8217;importe où on peut faire une requête HTTP vers le service de push de crossbar.</p>
<p>Ce message va être récupéré par notre client, où qu&#8217;il soit, puisqu&#8217;il est aussi connecté au routeur WAMP. Comme, je vous le rappelle, notre client fait ça :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">@</span>app.<span style="color: black;">subscribe</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'clientconfig.'</span> + app._params<span style="color: black;">&#91;</span><span style="color: #483d8b;">'ip'</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> update_configuration<span style="color: black;">&#40;</span>args<span style="color: black;">&#41;</span>:
    app._params.<span style="color: black;">update</span><span style="color: black;">&#40;</span>args<span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Il va recevoir ce message, et donc le contenu de <code>'args': [model_to_dict(instance)]</code>, c&#8217;est à dire la nouvelle configuration qu&#8217;on a changé en base de donnée. Il se met ainsi à jour immédiatement. La boucle est bouclée.</p>
<p>Comme on veut profiter de notre boucle toute bouclée, on rajoute le modèle dans l&#8217;admin :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">contrib</span> <span style="color: #ff7700;font-weight:bold;">import</span> admin
&nbsp;
<span style="color: #808080; font-style: italic;"># Register your models here.</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">from</span> django_app.<span style="color: black;">models</span> <span style="color: #ff7700;font-weight:bold;">import</span> Client
&nbsp;
admin.<span style="color: #dc143c;">site</span>.<span style="color: black;">register</span><span style="color: black;">&#40;</span>Client<span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Ainsi, les configs des clients seront éditables dans l&#8217;admin, et quand on cliquera sur &#8220;save&#8221;, ça va lancer notre publish WAMP qui mettra à jour le bon client.</p>
<p>Le reste, c&#8217;est du fignolage. Une petite vue pour créer ou récupérer notre configuration de client au démarrage :</p>

<div class="wp_syntax"><table><tr><td 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> json
&nbsp;
<span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">http</span> <span style="color: #ff7700;font-weight:bold;">import</span> HttpResponse
<span style="color: #ff7700;font-weight:bold;">from</span> django_app.<span style="color: black;">models</span> <span style="color: #ff7700;font-weight:bold;">import</span> Client
<span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">views</span>.<span style="color: black;">decorators</span>.<span style="color: black;">csrf</span> <span style="color: #ff7700;font-weight:bold;">import</span> csrf_exempt
<span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">forms</span>.<span style="color: black;">models</span> <span style="color: #ff7700;font-weight:bold;">import</span> model_to_dict
&nbsp;
&nbsp;
<span style="color: #66cc66;">@</span>csrf_exempt
<span style="color: #ff7700;font-weight:bold;">def</span> clients<span style="color: black;">&#40;</span>request<span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot; Récupère la config d'un client en base de donnée et lui envoie.&quot;&quot;&quot;</span>
    client<span style="color: #66cc66;">,</span> created <span style="color: #66cc66;">=</span> Client.<span style="color: black;">objects</span>.<span style="color: black;">get_or_create</span><span style="color: black;">&#40;</span>ip<span style="color: #66cc66;">=</span>request.<span style="color: black;">POST</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">'ip'</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> HttpResponse<span style="color: black;">&#40;</span>json.<span style="color: black;">dumps</span><span style="color: black;">&#40;</span>model_to_dict<span style="color: black;">&#40;</span>client<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span> content_type<span style="color: #66cc66;">=</span><span style="color: #483d8b;">'application/json'</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>On désactive la protection CSRF pour la démo, mais encore une fois, en prod, faites ça proprement, avec une jolie authentification pour protéger la vue, et tout, et tout.</p>
<p>Donc, cette vue récupère la configuration d&#8217;un client avec cette IP (la créant au besoin), et la retourne en JSON. Souvenez-vous, cela permet à notre client de faire :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">    app._params.<span style="color: black;">update</span><span style="color: black;">&#40;</span>requests.<span style="color: black;">post</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'http://'</span> + SERVER + <span style="color: #483d8b;">':8080/clients/'</span><span style="color: #66cc66;">,</span>
                                    data<span style="color: #66cc66;">=</span><span style="color: black;">&#123;</span><span style="color: #483d8b;">'ip'</span>: app._params<span style="color: black;">&#91;</span><span style="color: #483d8b;">'ip'</span><span style="color: black;">&#93;</span><span style="color: black;">&#125;</span><span style="color: black;">&#41;</span>.<span style="color: black;">json</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Au démarrage et se déclarer dans la base de données, tout en récupérant sa config.</p>
<p>On branche tout ça via <code>urls.py</code> :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">conf</span>.<span style="color: black;">urls</span> <span style="color: #ff7700;font-weight:bold;">import</span> patterns<span style="color: #66cc66;">,</span> include<span style="color: #66cc66;">,</span> url
<span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">contrib</span> <span style="color: #ff7700;font-weight:bold;">import</span> admin
<span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">views</span>.<span style="color: black;">generic</span> <span style="color: #ff7700;font-weight:bold;">import</span> TemplateView
&nbsp;
urlpatterns <span style="color: #66cc66;">=</span> patterns<span style="color: black;">&#40;</span><span style="color: #483d8b;">''</span><span style="color: #66cc66;">,</span>
    url<span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'^admin/'</span><span style="color: #66cc66;">,</span> include<span style="color: black;">&#40;</span>admin.<span style="color: #dc143c;">site</span>.<span style="color: black;">urls</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span>
    url<span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'^clients/'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'django_app.views.clients'</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span>
    url<span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'^$'</span><span style="color: #66cc66;">,</span> TemplateView.<span style="color: black;">as_view</span><span style="color: black;">&#40;</span>template_name<span style="color: #66cc66;">=</span><span style="color: #483d8b;">'dashboard.html'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span>
<span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>L&#8217;admin, notre vue toute fraiche, et de quoi servir le HTML du début de l&#8217;article.</p>
<p>Y plus qu&#8217;à :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="bash" style="font-family:monospace;">.<span style="color: #000000; font-weight: bold;">/</span>manage.py syncdb</pre></td></tr></table></div>

<h2>Crossbar.io</h2>
<p>Finalement, tout ce qu&#8217;il reste, c&#8217;est notre bon crossbar :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="bash" style="font-family:monospace;">crossbar init</pre></td></tr></table></div>

<p>Ceci nous pond le dossier <code>.crossbar</code> dans lequel on a le fichier <code>config.json</code> qu&#8217;on édite pour qu&#8217;il ressemble à ça :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #009900;">&#123;</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;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;wsgi&quot;</span><span style="color: #339933;">,</span>
                     <span style="color: #3366CC;">&quot;module&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;django_project.wsgi&quot;</span><span style="color: #339933;">,</span>
                     <span style="color: #3366CC;">&quot;object&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;application&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: #339933;">,</span>
                  <span style="color: #3366CC;">&quot;notify&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;pusher&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;role&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;anonymous&quot;</span>
                  <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span>
                  <span style="color: #3366CC;">&quot;static&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;../static&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: #009900;">&#93;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>La partie du haut c&#8217;est un peu l&#8217;équivalent du <code>chmod 777</code> de crossbar :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="javascript" style="font-family:monospace;">         <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;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></pre></td></tr></table></div>

<p>&#8220;Met moi en place un router avec un accès nommé realm1 qui autorise à tous les anonymes de tout faire&#8221;. Un realm est une notion de sécurité dans Crossbar.io qui permet de cloisonner les clients connectés, nous on va tout mettre sur le même realm, c&#8217;est pour une démo je vous dis.</p>
<p>Ensuite on rajoute les transports pour chaque techno qui nous intéresse. On va tout regrouper sur le port 8080 car Twisted peut écouter en HTTP et Websocket sur le même port :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="javascript" style="font-family:monospace;"><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></pre></td></tr></table></div>

<p>A la racine, on sert notre app Django :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="javascript" style="font-family:monospace;">  <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;wsgi&quot;</span><span style="color: #339933;">,</span>
     <span style="color: #3366CC;">&quot;module&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;django_project.wsgi&quot;</span><span style="color: #339933;">,</span>
     <span style="color: #3366CC;">&quot;object&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;application&quot;</span>
  <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span></pre></td></tr></table></div>

<p>Car oui, crossbar peut servir votre app django en prod. Pas besoin de gunicorn. En fait même pas besoin d&#8217;nginx pour un site simple, car ça tient très bien la charge. On a juste à lui indiquer quelle variable (<code>application</code>) de quel fichier WSGI (<code>django_project/wsgi.py</code>) charger, et il s&#8217;occupe du reste.</p>
<p>Sur &#8216;/ws&#8217;, on écoute en Websocket :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="javascript" style="font-family:monospace;"><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: #339933;">,</span></pre></td></tr></table></div>

<p>WAMP passe par là, et c&#8217;est pour ça que nos clients se connectent en faisant <code>app.run(url="ws://%s:8080/ws" % SERVER)</code> et <code>autobahn.Connection({url: 'ws://127.0.0.1:8080/ws', realm: 'realm1'});</code>.</p>
<p>&#8216;/notify&#8217; va recevoir le bridge WAMP-HTTP :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #3366CC;">&quot;notify&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;pusher&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;role&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;anonymous&quot;</span>
  <span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>Tous les anonymes du <code>realm1</code> peuvent l&#8217;utiliser. Grâce à ça, on a pu faire depuis notre signal Django :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">    requests.<span style="color: black;">post</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;http://127.0.0.1:8080/notify&quot;</span><span style="color: #66cc66;">,</span>
                  json<span style="color: #66cc66;">=</span><span style="color: black;">&#123;</span>
                      <span style="color: #483d8b;">'topic'</span>: <span style="color: #483d8b;">'clientconfig.'</span> + instance.<span style="color: black;">ip</span><span style="color: #66cc66;">,</span>
                      <span style="color: #483d8b;">'args'</span>: <span style="color: black;">&#91;</span>model_to_dict<span style="color: black;">&#40;</span>instance<span style="color: black;">&#41;</span><span style="color: black;">&#93;</span>
                  <span style="color: black;">&#125;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Et donc publier un message WAMP, via un POST HTTP.</p>
<p>Enfin, on sert les fichiers statiques Django avec Crossbar (oui, il fait aussi ça :):</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="javascript" style="font-family:monospace;"> <span style="color: #3366CC;">&quot;static&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;../static&quot;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>N&#8217;oubliez pas le de spécifier <code>STATIC_ROOT</code> dans le fichier settings et lancer <code>./manage.py collecstatic</code>.</p>
<p>Tout ça en place, on lance notre routeur :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #7a0874; font-weight: bold;">export</span> <span style="color: #007800;">PYTHONPATH</span>=<span style="color: #000000; font-weight: bold;">/</span>chemin<span style="color: #000000; font-weight: bold;">/</span>vers<span style="color: #000000; font-weight: bold;">/</span>votre<span style="color: #000000; font-weight: bold;">/</span>project
crossbar start</pre></td></tr></table></div>

<p>(Remplacer <code>export</code> par <code>set</code> sous Windows></p>
<p>La modification de <code>PYTHONPATH</code> est nécessaire pour que crossbar trouve votre fichier WSGI.</p>
<p>On visite <a href="http:127.0.0.1:8080/">http:127.0.0.1:8080/</a>, qui va charger notre template Django <code>dashboard.html</code>.</p>
<p>Chaque machine qui lance un client via <code>python client.py</code> va déclencher l&#8217;apparition des stats sur notre dashboard, qui seront mises à jour en temps réel.</p>
<p>Si on va sur <a href="http:127.0.0.1:8080/admin/">http:127.0.0.1:8080/admin/</a> et qu&#8217;on change la config d&#8217;un client, notre client s&#8217;adapte, et notre dashboard se met à jour automatiquement.</p>
<h2>Conclusion</h2>
<p>Notre projet ressemble à ceci au final :</p>
<pre>
.
├── client.py
├── .crossbar
│   ├── config.json
├── db.sqlite3
├── django_app
│   ├── admin.py
│   ├── __init__.py
│   ├── models.py
│   ├── templates
│   │   └── dashboard.html
│   └── views.py
├── django_project
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── static
└── manage.py

</pre>
<p>Vous pouvez récupérer le code <a href="https://github.com/sametmax/codes-des-articles/tree/master/2015/fevrier/tudo_django_wamp">ici</a>.</p>
<p>Finalement, très peu de code WAMP : un peu dans le JS, un peu dans le client. Et la seule chose qui lie WAMP à Django est la config crossbar qui ajoute le service HTTP PUSHER et notre requête POST dans <code>models.py</code></p>
<p>Cette technique n&#8217;est pas limitée à Django, et fonctionne bien pour toutes techno synchrones qui ne peut pas lancer un client WAMP directement en son sein. Pour le moment, le bridge HTTP-WAMP ne propose que PUB, pas de SUB, de pas de RPC. C&#8217;est déjà assez sympa pour avoir les notifications en temps réel un peu partout, et ça Tobias m&#8217;a dit qu&#8217;il ajoutera les autres actions dans un future proche.</p>
<p>En attendant, vous voyez le deal : on peut mélanger allègrement HTTP, WAMP, Python, JS, Client, Serveur, et monter sa petite architecture comme on le souhaite. Crossbar permet de démarrer du WSGI, mais aussi les clients WAMP sur la même machine et même n&#8217;importe quel process en ligne de commande (par exemple NodeJS) si besoin. C&#8217;est Mac Gyver ce truc.</p>
<p>On aurait pu écrire le client en Python 3 puisqu&#8217;il est sur une autre machine. Et en fait, si on lance Django en dehors de crossbar, aussi la partie Django en Python 3. Le code de crossbar n&#8217;est jamais modifié, on touche juste la configuration JSON.</p>
<p>Personnellement j&#8217;ai lancé plusieurs images <a href="http://sametmax.com/le-deploiement-par-conteneurs-avec-docker/">dockers</a> avec un client dedans à chaque fois, et c&#8217;est vraiment sympas de voir les machines se rajouter sur le dashboard en temps réel. On a une super sensation d&#8217;interactivité quand on change une valeur dans l&#8217;admin et qu&#8217;on voit le dashboard bouger.</p>


feed_id: http://sametmax.com/?p=15894
title: Et ça repart 11
uri: Et-ça-repart
url: http://sametmax.com/et-ca-repart/
content:
<p>Je me barre un mois dans la nature. </p>
<p>J&#8217;aurai pas d&#8217;ordi, donc pas de nouveaux posts sauf si Max se sort les doigts du fion.</p>
<p>Profitez-en pour relire les anciens articles :)</p>


feed_id: http://sametmax.com/?p=15951
title: Le don du mois : VLC 6
uri: Le-don-du-mois-VLC-3
url: http://sametmax.com/le-don-du-mois-vlc/
content:
<p>Le concept du don du mois <a href="https://blog.sciunto.org/posts/don_archlinux/">fait des emules</a>, et c&#8217;est bien. Que nous réserve donc mars ?</p>
<p>Un petit flasback, comme souvent.</p>
<p>Souvenez-vous, ce temps des packs de codecs buggés et vérolés. Des multiples lecteurs à installer. Des fichiers incomplets ou corrompus illisibles pour un bit de travers. De votre ordi qui rame car le film est trop compressées. L&#8217;ère pré-historique de la lecture de vidéo.</p>
<p>Et puis, cocorico !</p>
<p>A l&#8217;école Centrale de Paris, des élèves décident de streamer des films entre deux points de leur internat, et ainsi naquis VLC. </p>
<p>Qui lit tout. Même les .mov, les trucs fait pour realplayer, les .ogg, les videos streamées, les films cassés, les DVD chiffrés ou zonés&#8230; Tout, en prenant le minimum de ressource. Avec tellement d&#8217;options en plus : les sous-titre, le décalage du son, le transcoding, le changement d&#8217;orientation, de format, de pitch, le saut des pubs, etc. Et il existe des interfaces ncurse, HTTP et telnet !</p>
<p>Cerise sur le gâteau, ça marche sur Mac. Sur Linux. Et sur Windows, en un exe, qu&#8217;on peut rendre portable sur clé USB. Et depuis la dernière version, sur mobile.</p>
<p>La fondation VLC <a href="http://www.videolan.org/contribute.html">accepte les bitcoins</a> et reçoit donc 50€ d&#8217;amour inconditionnel.</p>


feed_id: http://sametmax.com/?p=15938
title: Je suis très attachant 9
uri: Je-suis-très-attachant-8-Recently-updated
url: http://sametmax.com/je-suis-tres-attachant/
content:
<p>Je n&#8217;ai rien contre le fait d&#8217;être attaché de temps en temps, mais il est vrai que je préfère attacher. Pas que ce soit une pratique quotidienne, pas plus que manger des frites à Mac Do, mais de temps en temps avec des amis c&#8217;est sympa.</p>
<p>Maintenant, quand on attache, il faut se poser la question de quoi, sur quoi, avec quoi et comment.</p>
<div id="attachment_15943" style="width: 259px" class="wp-caption aligncenter"><a href="media/4497fc38.images.jpeg" data-original-source="http://sametmax.com/wp-content/uploads/2015/03/images.jpeg" class="grouped_elements" rel="tc-fancybox-group15938"><img class="size-full wp-image-15943" src="media/4497fc38.images.jpeg" data-original-source="http://sametmax.com/wp-content/uploads/2015/03/images.jpeg" alt="Bondage, weall started somewhere" width="249" height="202" /></a><p class="wp-caption-text">Personne ne naît expert en ligotage</p></div>
<h2>Quoi</h2>
<p>Les bras, en priorité. C&#8217;est ce qui donne le plus de sensations.</p>
<p>Les chevilles en second, si on a la possibilité.</p>
<div id="attachment_15946" style="width: 810px" class="wp-caption aligncenter"><a href="media/5589f186.captive_bondage_7__c__by_mostlyguystock-d679tu5.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2015/03/captive_bondage_7__c__by_mostlyguystock-d679tu5.jpg" class="grouped_elements" rel="tc-fancybox-group15938"><img class="size-full wp-image-15946" src="media/5589f186.captive_bondage_7__c__by_mostlyguystock-d679tu5.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2015/03/captive_bondage_7__c__by_mostlyguystock-d679tu5.jpg" alt="Homme attaché" width="800" height="786" /></a><p class="wp-caption-text">On est pas obligé d&#8217;attacher à quelque chose en particulier</p></div>
<p>Après le reste n&#8217;est pas aussi important, c&#8217;est du bonus, c&#8217;est contextuel.</p>
<p>On peut attacher les bras aux chevilles pour donner un sentiment d&#8217;abandon total.</p>
<p>On peut attacher le cou pour le côté &#8220;laisse&#8221;.</p>
<p>Plus rare, mais intéressant, on peut attacher le taille en formant un harnais. Parfois pour suspendre le partenaire, parfois juste pour l’empêcher de gigoter. C&#8217;est quelque chose qu&#8217;on fait quand on veut donner un coup de pouce dans la progression de ce que peut supporter l&#8217;autre. Néanmoins le point d&#8217;attache est plus difficile à trouver. Astuce : si on ne peut pas attacher en face, diviser la corde ou autre, en deux, et attacher de part et d&#8217;autre. C&#8217;est presque aussi efficace.</p>
<p>On peut attacher les cheveux à quelque chose, mais c&#8217;est advanced, je le recommande pas aux débutants. Contrairement au cou, ce n&#8217;est pas très dangereux, mais il y a beaucoup de manière de casser l&#8217;ambiance avec cette idée.</p>
<p>On peut ligoter les seins. Bien entendu, le but n&#8217;est pas d&#8217;empêcher la personne de se débattre à coup de tétons, mais bien, pour certaines qui aiment cela, d&#8217;avoir les mamelles en tension. Dans le même registre, un bâillon est une forme d&#8217;attachement. Une chaussette dans la bouche et un bout de scotch font l&#8217;affaire. Perso j&#8217;aime bien la gags ball (c&#8217;est psychologique), mais c&#8217;est dur d&#8217;entre trouver à la bonne taille car la plupart sont trop grosses.</p>
<p>Et enfin, on peut attacher tout le corps pour un effet d&#8217;emprisonnement total.</p>
<p>Comme d&#8217;habitude, ce que vous allez attacher n&#8217;est pas juste dépendant du résultat que vous voulez obtenir, mais également de ce que peut accepter l&#8217;autre. Néanmoins, ne flippez pas : essayez, et si on vous dit non, essayez autre chose. Inutile de vous demander pendant des heures si oui ou non ça va le faire. Même demander directement à la personne n&#8217;est pas toujours une bonne solution, entre ceux qui ne savent pas ce qu&#8217;ils aiment, ceux qui n&#8217;osent pas l&#8217;avouer et ceux pour qui en parler leur retire l&#8217;excitation. Un peu comme quand vous voyez un enfant dire à un autre &#8220;tu veux sortir avec moi ?&#8221;. Adulte, ça vous paraîtrait non naturel de le demander à haute voix, et généralement une relation commence par la tentative d&#8217;un baiser, non la demande de permission de le faire.</p>
<p>Donc essayez, mais sans brusquer. Sans surprise. Montrez clairement ce que vous êtes en train de faire. Donnez le temps à la personne de dire non.</p>
<p>C&#8217;est l&#8217;éternel problématique du sexe : notre société vous dit qu&#8217;il faut demander la permission pour tout sinon vous êtes pire qu&#8217;Hitler, mais dans la pratique les personnes avec une sexualité avancée ne demandent pas tout. Certaines choses sont justes tentées, et on s&#8217;adapte au résultat et à la réaction. Il y a donc une véritable prise de risque social, comme souvent avec les trucs un peu fun.</p>
<p>Ça n&#8217;enlève pas le fait qu&#8217;il faut AVOIR la permission pour continuer quoique ce soit. Simplement que vous ne pouvez pas toujours la demander explicitement.</p>
<p>Dans les milieux SM expérimentés, il n&#8217;est cependant pas rare d&#8217;avoir des questionnaires à remplir au préalable pour que chacun sache ce qu&#8217;il peut faire ou pas. Mais le plupart des gens n&#8217;en sont pas à ce degré d&#8217;aisance sexuelle (tiens, je sais qu&#8217;on se connaît depuis une semaine, mais rempli ce questionnaire avant qu&#8217;on baise steupl). Et croyez-moi, ils font des trucs plus hard que de mettre une laisse.</p>
<h2>Sur quoi</h2>
<p>Bien entendu, les barreaux de lit viennent en première idée, et le radiateur en second. Mais on peut innover.</p>
<p>On peut s&#8217;attacher l&#8217;un à l&#8217;autre, de différentes manières. Une corde en corps à corps. Une main à une main. Une laisse du cou de l&#8217;un à la hanche de l&#8217;autre.</p>
<div id="attachment_15940" style="width: 535px" class="wp-caption aligncenter"><a href="media/57b1b879.bamboo-bondage-video.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2015/03/bamboo-bondage-video.jpg" class="grouped_elements" rel="tc-fancybox-group15938"><img class="size-full wp-image-15940" src="media/57b1b879.bamboo-bondage-video.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2015/03/bamboo-bondage-video.jpg" alt="Double bondage" width="525" height="295" /></a><p class="wp-caption-text">Nul besoin d&#8217;aller si loin, même attacher une seule main peut suffire à mettre la bonne ambiance</p></div>
<p>On peut s&#8217;attacher à une chaise, bien entendu. Les chaises roulantes sont marrantes 5 minutes, mais pas pratiques.</p>
<p>Un truc bien sympa est d&#8217;avoir un accessoire pour suspendre. Un crochet par exemple, attaché <strong>très solidement</strong> au mur ou au plafond. Une mezzanine avec des barreaux (chez Ikea ce sont de sacrés coquins) se prête naturellement à cela.</p>
<p>J&#8217;ai quand même une astuce spécial bricolo pour vous : prenez des attaches de sex shop, et faites un gros nœud d&#8217;un coté, puis passez les au dessus d&#8217;une porte qui ferme bien. Le nœud coincera les attaches dans le haut de la porte, et vous pouvez suspendre tout à loisir contre la porte. Avantage : ça s&#8217;enlève facilement après la séance.</p>
<p>Une chose à laquelle on pense plus rarement : attacher à un gros objet lourd mais transportable, à traîner comme un boulet de prisonnier. C&#8217;est utile surtout pour les scénarios domi de longue durée, par pour chahuter au goûter, mais les gens ne s&#8217;y attendent pas. Faites gaffe que le truc ne raye pas le parquet, ça m&#8217;a coûté une caution.</p>
<p>Si vous avez la chance de visiter des clubs SM, vous rentrerez avec tout un tas de supports inédits pour s&#8217;attacher : des croix, des tables spéciales, des &#8220;chevaux&#8221; de bois, etc. C&#8217;est impressionnant, et tout le monde n&#8217;a pas envie ni besoin d&#8217;aller aussi loin, mais il est bon de savoir que ça existe. Ça peut inspirer pour chez soi.</p>
<p>A ne pas tenter :</p>
<ul>
<li>Les tuyaux. C&#8217;est fragile et ça casse. Une inondation n&#8217;est pas un préliminaire apprécié.</li>
<li>Les pieds de meuble. C&#8217;est très dangereux.</li>
</ul>
<h2>Avec quoi</h2>
<p>Des choses larges. Les petites attaches coupent la circulation du sang, et peuvent être dangereuses. Je ne vais pas jeter la pierre, moi aussi j&#8217;ai attaché avec des lacets dans le feu de l&#8217;action, mais ce n&#8217;est pas idéal.</p>
<p>Les ceintures font de meilleures attaches improvisées.</p>
<p>En matière de corde, prenez de la grosse corde (chez Jardiland ce sont de sacrés coquins), et essayez la sur vous. Plusieurs longueurs sont utiles : courtes pour les brases et les jambes, longues pour les hanches ou le cou, très longue pour tout le corps, genre total bondage.</p>
<div id="attachment_15941" style="width: 346px" class="wp-caption aligncenter"><a href="media/0b89f865.shibari-shibari-demotivational-posters-1335908917.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2015/03/shibari-shibari-demotivational-posters-1335908917.jpg" class="grouped_elements" rel="tc-fancybox-group15938"><img class="size-full wp-image-15941" src="media/0b89f865.shibari-shibari-demotivational-posters-1335908917.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2015/03/shibari-shibari-demotivational-posters-1335908917.jpg" alt="Shibari" width="336" height="486" /></a><p class="wp-caption-text">Evidemment, les japonais ont trouvé le moyen d&#8217;en faire une forme d&#8217;art. Qui d&#8217;autres ?</p></div>
<p>Mais l&#8217;idéal pour débuter, ce sont encore les produits des sex shops. Beaucoup sont nuls à chier, il faut donc les essayer. Généralement, les attaches pour les bras et jambes sont pas mal. Un truc sympa qu&#8217;on ne trouve que dans ces boutiques ou sur le net, ce sont des rubans adhésifs qui se collent uniquement à eux même. Ça ne colle pas à la peau ni aux vêtements. On peut faire des choses intéressantes avec.</p>
<p>Sinon évidemment, le gros scotch gris est top pour un scénario type kidnapping. Évitez les zones poilues et les tissues fragiles, sauf si vous savez que ça plaît. Les attaches plastiques rapides, qui sont assez fines donc faites gaffe, brillent quand la rapidité de mise en place et la solidité sont importantes. Et elles permettent de créer de nouvelles zones d&#8217;attache ou d&#8217;en lier plusieurs (chez Bricorama ce sont de sacrés coquins).</p>
<p>De manière surprenante, les boutiques de sécurité (là où se fournissent les flics, gardiens, CRS, garde du corps, qui sont de sacrés coquins) possèdent plein de choses qui peuvent être détournées. Non, je ne parle pas des tasers bande d&#8217;abrutis, mais des différentes variantes des menottes (bien meilleures que celles des sex shop) et autres outils pour maîtriser &#8220;une menace&#8221;. Ne faites pas n&#8217;importe quoi néanmoins, ces magasins possèdent des choses dangereuses qui ne sont pas faites pour faire mumuse. Vous êtes des adultes (j&#8217;espère :)), vous vous devez le bon sens, dans le cas contraire je m&#8217;assurerai que vous receviez le Darwin Award qui vous est dû.</p>
<p>Autre source peu connue de matériel cochon, les hôpitaux (qui sont pleins de sacrés coquins), et particulièrement les départements avec des patients subissant des traitements invasifs, en grande douleur ou en internement psychiatrique. Sans aller jusqu&#8217;à la camisole de force, que je n&#8217;ai pas eu le plaisir de tester, les attaches des lits sont à la fois très polyvalentes (on peut les combiner, les ajuster et les attacher à presque n&#8217;importe quoi) et très confortables (on peut tirer dessus très fort sans blesser la personne). J&#8217;ai des amis infirmiers qui m&#8217;ont fourni en la matière, et c&#8217;est super chouette.</p>
<p>Enfin, si vous avez les moyens, les balançoires et autres outils de suspensions SM sont très, très fun, mais demandent une installation contraignante.</p>
<h2>Comment</h2>
<p>Avec concentration.</p>
<div id="attachment_15942" style="width: 760px" class="wp-caption aligncenter"><a href="media/59e924b5.base_red_leather_bondage_spock__2x_by_spock2u-d5xmcc7.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2015/03/base_red_leather_bondage_spock__2x_by_spock2u-d5xmcc7.jpg" class="grouped_elements" rel="tc-fancybox-group15938"><img class="size-full wp-image-15942" src="media/59e924b5.base_red_leather_bondage_spock__2x_by_spock2u-d5xmcc7.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2015/03/base_red_leather_bondage_spock__2x_by_spock2u-d5xmcc7.jpg" alt="Spock bondage" width="750" height="1065" /></a><p class="wp-caption-text">Il faut rester logique</p></div>
<p>On peut faire un peu mal. On peut fournir un peu d&#8217;inconfort. Ou plus. Ou moins. A doser selon l&#8217;attaché(e).</p>
<p>Mais la sécurité est importante.</p>
<p>Si tout ce que vous faites est d&#8217;attacher la personne aux barreaux du lit, le pire qu&#8217;il puisse vous arriver sont des poignets un peu rouges.</p>
<p>Mais dès que vous faites de la laisse, de la suspension ou des attaches sur plusieurs parties du corps, il faut réfléchir à ce que vous faites.</p>
<p>Et c&#8217;est ce que beaucoup de personnes ne comprennent pas, dans un moment de bestialité sexuelle, qu&#8217;on doive avoir la maturité et la discipline de prendre du recul. Mais c&#8217;est comme ça que la confiance se construit, qu&#8217;on peut aller de plus en plus loin, et qu&#8217;on s&#8217;amuse.</p>
<p>Quelques conseils mécaniques : essayez d&#8217;orienter les attaches aux poignets de telle sorte que la corde appuie plus sur l&#8217;extérieur du bras qu&#8217;à l&#8217;intérieur (où sont les veines). Par exemples, si vous utilisez un zipper plastique, mettez l’intérieur des bras l&#8217;un contre l&#8217;autre, ou contre une surface, pour immobiliser les deux mains à la fois. Si vous serrez fort, ce sera désagréable, mais pas dangereux.</p>
<p>Pas évident si vous avez convenu que la personne se débattrait pendant l&#8217;acte, j&#8217;en conviens. Des fois ça donne des sessions fou-rire et ça finit n&#8217;importe comment :)</p>
<p>Les attaches des chevilles ne sont pas très risquées, donc si vous voulez tirer sur quelque chose, ici, vous pouvez.</p>
<p>A moins que vous sachiez très bien ce que vous faites, contrairement aux bras et aux jambes qui peuvent être en tension pour renforcer le sentiment d&#8217;emprisonnement, le cou doit toujours avoir du mou et jamais avec un angle possible dans lequel on peut se coincer et se blesser. Il y a 3 choses à vérifier : s&#8217;assurer que la trachée n&#8217;est pas écrasée pour laisser passer l&#8217;air et ne pas casser la voix, que les jugulaires ne sont pas bloquées pour assurer un flux sanguin, et que la nuque ne subit pas de pression. Souvenez-vous : le collier, c&#8217;est du jeu. Il existe des personnes qui aiment être étranglées, mais elles sont rares, et ça demande de l&#8217;attention de la part de celui qui étrangle. Il y a des gens qui meurent chaque année à cause d’asphyxie érotiques mal maîtrisées.</p>
<div id="attachment_15945" style="width: 269px" class="wp-caption aligncenter"><a href="media/e23d753d.laisse.jpeg" data-original-source="http://sametmax.com/wp-content/uploads/2015/03/laisse.jpeg" class="grouped_elements" rel="tc-fancybox-group15938"><img class="size-full wp-image-15945" src="media/e23d753d.laisse.jpeg" data-original-source="http://sametmax.com/wp-content/uploads/2015/03/laisse.jpeg" alt="Laisse avec du mou" width="259" height="194" /></a><p class="wp-caption-text">Ca ne veut pas dire que vous ne pouvez pas tirer sur la laisse. Ca veut dire qu&#8217;il faut gérer.</p></div>
<p>Le porno hard que vous voyez en ligne est fait par des professionnels. Tout paraît toujours simple quand on voit une scène, mais ils ont l&#8217;habitude, et la préparation.</p>


feed_id: http://sametmax.com/?p=15915
title: Je sais, je vous ai manqué 10
uri: Je-sais-je-vous-ai-manqué-9
url: http://sametmax.com/je-sais-je-vous-ai-manque/
content:
<p>Mais à partir de demain les articles reprennent. Faudra que je depop tous les mails, les tickets github, répondre aux commentaires, checker indexerror, etc.</p>
<p>Ca va prendre du temps, mais ça repart.</p>
<p>Je ferai bien un article de cul pour faire une rentrée sur le pompier. Heu le bon pied.</p>


feed_id: http://sametmax.com/?p=15963
title: Tableau de référence des exceptions en Python 6
uri: Tableau-de-référence-des-exceptions-en-Python
url: http://sametmax.com/tableau-de-reference-des-exceptions-en-python/
content:
<p>J&#8217;ai fais un topo sur <a href="http://sametmax.com/gestion-des-erreurs-en-python/">la gestion des erreurs en python</a>, mais je pense que les débutants peuvent bénéficier d&#8217;un petit tableau pour s&#8217;y retrouver quand ils tombent sur les erreurs les plus courantes.</p>
<p>Les exceptions suivantes sont levées en cas d&#8217;erreur. Elles héritent toutes de <code>StandardError</code> :</p>
<table class="tableizer-table">
<th>Exception</th>
<th>Cause</th>
<th>Résolution</th>
</tr>
<tr>
<td>NotImplementedError</td>
<td>Un développeur a volontairement levé cette exception dans une des méthodes de sa classe afin de signaler que c&#8217;est aux enfants de la classe de l&#8217;implémenter.</td>
<td>N&#8217;utilisez pas la classe directement, mais créez une classe enfant. Overridez la méthodes afin de lui donner un comportement. Si vous ne comprenez pas ce que je viens de dire, lisez le <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/">guide sur la POO</a>.</td>
</tr>
<tr>
<td>IndentationError ou TabError</td>
<td>Le fichier mélange des tabs et des espaces ou n&#8217;utilisent pas le même nombre de tabs ou d&#8217;espaces partout.</td>
<td>Activez l&#8217;affichage des tabs et espaces dans votre éditeur de texte, et assurez-vous d&#8217;utiliser 4 espaces partout comme valeur d&#8217;indentation.</td>
</tr>
<tr>
<td>ImportError</td>
<td>Python ne peut pas importer un module.</td>
<td>Vérifier que le nom du module ne comporte pas de fautes (Python est sensible à la casse). Assurez-vous que le module est importable (situé dans un dossier du PYTHON PATH) et qu&#8217;il ne contient pas d&#8217;erreurs empêchant son importation, telle qu&#8217;une référence cyclique. Si vous ne savez pas ce qu&#8217;est le PYTHON PATH, lisez l&#8217;<a href="http://sametmax.com/les-imports-en-python/">article sur les imports</a>.</td>
</tr>
<tr>
<td>AssertionError</td>
<td>Une expression <code>assert</code> est fausse.</td>
<td>Si c&#8217;est dans votre code, retirez le <code>assert</code>, ce mot clé n&#8217;est que pour les tests unittaires. Si vous avez la malchance de tomber sur une lib qui l&#8217;utilise comme garde fou pour le passage d&#8217;arguments valeur, lisez le code source, et passez une valeur qui rendra l&#8217;expression vraie. Si vous en avez dans les tests et que vous ne savez pas quoi en faire, lisez le <a href="http://sametmax.com/un-gros-guide-bien-gras-sur-les-tests-unitaires-en-python-partie-1/">guide sur le tests.</a></td>
</tr>
<tr>
<td>AttributeError</td>
<td>Vous demandez à un objet de vous fournir un attribut qu&#8217;il ne possède pas.</td>
<td>Vérifiez que le nom de l&#8217;attribut et le nom de l&#8217;objet ne contiennent pas de faute (Python est sensible à la casse). Vérifier que l&#8217;attribut a bien été créé avant son accès et pas supprimé entre temps (Python est dynamique, les attributs peuvent être créés et supprimés à la volée. Si le cas où l&#8217;attribut n&#8217;existe pas est un cas valide, vous pouvez tester cette existence avec <a href="https://docs.python.org/3/library/functions.html?highlight=hasattr#hasattr">hasattr()</a> ou obtenir une valeur par défaut avec <a href="https://docs.python.org/3/library/functions.html?highlight=getattr#getattr">getattr()</a>.</td>
</tr>
<tr>
<td>NameError</td>
<td>Vous tentez d&#8217;utiliser un nom (de variable, fonction, classe, etc) qui n&#8217;existe pas.</td>
<td>Vérifiez que ce nom ne contient pas de faute (Python est sensible à la casse). Assurez-vous que ce que vous nommez a bien été créé avant cette ligne.</td>
</tr>
<tr>
<td>IndexError</td>
<td>Vous tentez d&#8217;accéder à une partie d&#8217;une indexable (souvent une liste ou un tuple) qui n&#8217;existe pas.</td>
<td>Assurez vous que l&#8217;indexable contient assez d&#8217;éléments. Si le cas d&#8217;un indexable trop court est normal, vous pouvez vérifier la longueur de l&#8217;indexable avec <a href="https://docs.python.org/3/library/functions.html?highlight=getattr#len">len()</a>, ou utilisez un try/except.</td>
</tr>
<tr>
<td>KeyError</td>
<td>Vous tentez d&#8217;accéder à une clé d&#8217;un mapping (souvent un dictionnaire) qui n&#8217;existe pas.</td>
<td>Assurez vous que la clé existe. Si le cas d&#8217;une clé inexistante est normal, vous pouvez vérifier qu&#8217;une clé est dans le mapping avec &#8216;in&#8217;, utiliser try/except ou obtenir une valeur par défaut avec <a href="https://docs.python.org/3/library/stdtypes.html?highlight=dict.get#dict.get">get()</a>. Dans le cas où vous souhaitez aussi que la valeur par défaut soit ajoutée à la collection, utilisez <a href="https://docs.python.org/3/library/stdtypes.html?highlight=dict.setdefault#dict.setdefault">setdefault()</a> ou <a href="https://docs.python.org/3/library/collections.html?highlight=defaultdict#collections.defaultdict">collection.defaultdict()</a>.</td>
</tr>
<tr>
<td>TypeError</td>
<td>Vous tentez une opération incompatible avec ce type.</td>
<td>Si l&#8217;erreur a lieu au niveau d&#8217;une fonction que vous appelez, assurez-vous de passer des paramètres du type attendu par la fonction. Vous pouvez vérifier le type d&#8217;un objet avec <a href="https://docs.python.org/3/library/functions.html?highlight=type#type">type()</a>. Vérifiez également que vous n&#8217;utilisez pas un opérateur incompatible avec un type (par exemple, &#038; ne fonctionne pas sur les strings) ou entre deux types incompatibles (par exemple, il n&#8217;est pas possible d&#8217;additionner une string avec un entier).</td>
</tr>
<tr>
<td>ValueError</td>
<td>Vous passez une valeur à une fonction qui n&#8217;a aucun sens dans ce contexte ou dont le sens est ambiguë.</td>
<td>Assurez-vous de ne pas passer une valeur aberrante et que le résultat attendu soit évident. Par exemple, si vous essayez de faire int(&#8216;é&#8217;), la conversion de la lettre &#8220;é&#8221; en entier n&#8217;a pas de résultat évident.</td>
</tr>
<tr>
<td>UnicodeDecodeError</td>
<td>Vous gérez votre texte comme un porc.</td>
<td>Lisez <a href="http://sametmax.com/lencoding-en-python-une-bonne-fois-pour-toute/">le guide sur l&#8217;encoding</a>.</td>
</tr>
<tr>
<td>UnicodeEncodeError</td>
</tr>
<tr>
<td>OverflowError</td>
<td>Vous faites des calculs trop gros pour les types numériques des base</td>
<td>Utilisez le module <a href="https://docs.python.org/3/library/decimal.html?highlight=decimal#module-decimal">decimal</a></td>
</tr>
<tr>
<td>ZeroDivisionError</td>
<td>Vous faites une division par zéro</td>
<td>Assurez-vous que sous aucune condition aucun dénominateur n&#8217;est égal à 0</td>
</tr>
<tr>
<td>IOError</td>
<td>Erreur d&#8217;entrée / sortie </td>
<td>Vérifiez que vous pouvez lire / écrire depuis et vers la ressource que vous utilisez. Parmi les problèmes récurrents : disque dur plein, système corrompu, absence de permissions, fichier inexistant, etc.</td>
</tr>
<tr>
<td>OSError</td>
<td>L&#8217;OS retourne une erreur</td>
<td>Les causes peuvent être très variées, mais concernent souvent le système de fichier ou l&#8217;utilisation d&#8217;un sous-process. Vérifier les lignes où vous utiliser les modules os, shutils, popen, subprocess, multiprocessing, etc.</td>
</tr>
<tr>
<td>MemoryError</td>
<td>Vous utilisez trop de mémoire</td>
<td>Vérifiez vos remplissages de listes et dictionnaires, particulièrement si vous en déclarez un comme valeur par défaut d&#8217;un paramètre.</td>
</tr>
</table>
<p>Je n&#8217;ai pas mentionné quelques exceptions beaucoup plus rares, mais vous pouvez trouver la liste complète <a href="https://docs.python.org/2/library/exceptions.html">ici</a>.</p>
<p>Toutes les exceptions héritent de <code>BaseException</code>, y compris <code>Exception</code>. </p>
<p>Il existe 3 exceptions qui n&#8217;héritent pas de <code>Exception</code>, et ne représentent PAS des erreurs : </p>
<ul>
<li><code>SystemExit</code> : levé par <a href="https://docs.python.org/3/library/sys.html?highlight=sys.exit#sys.exit">sys.exit()</a> qui par nature met fin au programme. N&#8217;affiche pas de stack trace quand la VM s&#8217;arrête si elle n&#8217;est pas attrapée.</li>
<li><code>KeyboardInterrupt</code> : levé par des combinaison de touches au clavier qui par nature mettent fin au programme (comme <kbd>Ctrl</kbd> + <kbd>C</kbd>).</li>
<li><code>GeneratorExit</code> : levé automatiquement quand on appelle <code>close()</code> sur un générateur.</li>
</ul>
<p>Bien qu&#8217;héritant d&#8217;<code>Exception</code>, les <a href="https://docs.python.org/3/library/warnings.html?highlight=warning#module-warnings">warnings</a> sont des mécanismes un peu particulier. Ils sont tous notés XxxWarning (ex: <code>DeprecationWarning</code> pour signaler l&#8217;usage d&#8217;une fonctionnalité en cours de dépréciation) et sont des enfants de <code>Warning</code>.</p>
<p>Généralement les warnings ne sont pas fait pour être levés avec <code>raise</code>, mais appelé avec <a href="https://docs.python.org/3/library/warnings.html?highlight=warnings.warn#warnings.warn">warnings.warn</a>. Par défaut ces warnings sont affichés, mais peuvent être réduits au silence, filtrés ou levés comme exception selon le désir du développeur.</p>
<p>Enfin, <code>StopIteration</code> est levée quand on appelle <code>next()</code> sur un itérateur vide. C&#8217;est le seul enfant de <code>Exception</code> (avec <code>Warning</code>) qui n&#8217;hérite pas de <code>StandardError</code> car ce n&#8217;est pas une erreur en soit, mais simplement un mécanisme de contrôle de flux qui dit à la boucle <code>for</code> quand s&#8217;arrêter. </p>


feed_id: http://sametmax.com/?p=15993
title: Views VS generators 6
uri: Views-VS-generators
url: http://sametmax.com/views-vs-generators/
content:
<p>Avec Python 2.7, un outil appelé les &#8220;views&#8221; (les &#8220;vues&#8221;) est apparu. Une vue est juste un enrobage qui permet de voir un objet d&#8217;une certaine façon, et de le manipuler d&#8217;une certaine façon (avec une autre API), sans changer cet objet.</p>
<p>Les vues ont surtout été notables pour leur apparition dans les dictionnaires avec Python 2.7:</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">    <span style="color: #66cc66;">&gt;&gt;&gt;</span> scores <span style="color: #66cc66;">=</span> <span style="color: black;">&#123;</span><span style="color: #483d8b;">&quot;sam&quot;</span>: <span style="color: #ff4500;">1</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">&quot;max&quot;</span>: <span style="color: #ff4500;">0</span><span style="color: black;">&#125;</span>
    <span style="color: #66cc66;">&gt;&gt;&gt;</span> scores.<span style="color: black;">items</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># retourne une lsite</span>
    <span style="color: black;">&#91;</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'max'</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span> <span style="color: black;">&#40;</span><span style="color: #483d8b;">'sam'</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span>
    <span style="color: #66cc66;">&gt;&gt;&gt;</span> scores.<span style="color: black;">iteritems</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># retourne un générateur</span>
    <span style="color: #66cc66;">&lt;</span>dictionary-itemiterator <span style="color: #008000;">object</span> at <span style="color: #ff4500;">0x7f8782a26628</span><span style="color: #66cc66;">&gt;</span>
    <span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #008000;">list</span><span style="color: black;">&#40;</span>scores.<span style="color: black;">iteritems</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;"># sans views</span>
    <span style="color: black;">&#91;</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'max'</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span> <span style="color: black;">&#40;</span><span style="color: #483d8b;">'sam'</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span>
    <span style="color: #66cc66;">&gt;&gt;&gt;</span> scores.<span style="color: black;">viewsitems</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># avec views</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-dc0b08011047&gt;&quot;</span><span style="color: #66cc66;">,</span> line <span style="color: #ff4500;">1</span><span style="color: #66cc66;">,</span> <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #66cc66;">&lt;</span>module<span style="color: #66cc66;">&gt;</span>
        scores.<span style="color: black;">viewsitems</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># avec views</span>
    <span style="color: #008000;">AttributeError</span>: <span style="color: #483d8b;">'dict'</span> <span style="color: #008000;">object</span> has no attribute <span style="color: #483d8b;">'viewsitems'</span>
&nbsp;
    <span style="color: #66cc66;">&gt;&gt;&gt;</span> scores.<span style="color: black;">viewitems</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># retourne une vue</span>
    dict_items<span style="color: black;">&#40;</span><span style="color: black;">&#91;</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'max'</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span> <span style="color: black;">&#40;</span><span style="color: #483d8b;">'sam'</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Néanmoins personne ne les a vraiment utilisé, et c&#8217;est un tort. Elles sont en effet très performantes, et pour cette raison sont retournées par défaut avec <code>items()</code> en Python 3.</p>
<p>En effet, les vues ne sont qu&#8217;un enrobage : elles ne contiennent rien, et donc ne prennent pas beaucoup mémoire, tout comme les générateurs.</p>
<p>Mais contrairement aux générateurs, les vues ne se vident pas et peuvent exposer une API plus complète que les générateurs, comme par exemple déclarer une taille :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> items <span style="color: #66cc66;">=</span> scores.<span style="color: black;">iteritems</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #008000;">list</span><span style="color: black;">&#40;</span>items<span style="color: black;">&#41;</span>
<span style="color: black;">&#91;</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'max'</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span> <span style="color: black;">&#40;</span><span style="color: #483d8b;">'sam'</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">1</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;">list</span><span style="color: black;">&#40;</span>items<span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># woops</span>
<span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> items <span style="color: #66cc66;">=</span> scores.<span style="color: black;">viewitems</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #008000;">list</span><span style="color: black;">&#40;</span>items<span style="color: black;">&#41;</span>
<span style="color: black;">&#91;</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'max'</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span> <span style="color: black;">&#40;</span><span style="color: #483d8b;">'sam'</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">1</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;">list</span><span style="color: black;">&#40;</span>items<span style="color: black;">&#41;</span>
<span style="color: black;">&#91;</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'max'</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span> <span style="color: black;">&#40;</span><span style="color: #483d8b;">'sam'</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">1</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;">len</span><span style="color: black;">&#40;</span>scores.<span style="color: black;">iteritems</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;"># nope</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-21-9c7f250da51d&gt;&quot;</span><span style="color: #66cc66;">,</span> line <span style="color: #ff4500;">1</span><span style="color: #66cc66;">,</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;">len</span><span style="color: black;">&#40;</span>scores.<span style="color: black;">iteritems</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #008000;">TypeError</span>: <span style="color: #008000;">object</span> of <span style="color: #008000;">type</span> <span style="color: #483d8b;">'dictionary-itemiterator'</span> has no <span style="color: #008000;">len</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>scores.<span style="color: black;">viewitems</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #ff4500;">2</span></pre></td></tr></table></div>

<p>Alors certes, on ne peut pas mettre des vues partout, et les générateurs restent utiles. Mais quand il est possible de les utiliser, et à moins d&#8217;avoir besoin d&#8217;une liste afin de modifier les valeurs in place, il n&#8217;y pas de raison de ne pas le faire : c&#8217;est le meilleur des deux mondes. </p>


feed_id: http://sametmax.com/?p=16001
title: Reportez, il en restera toujours quelque chose 4
uri: Reportez-il-en-restera-toujours-quelque-chose-3
url: http://sametmax.com/reportez-il-en-restera-toujours-quelque-chose/
content:
<p>L&#8217;année dernière j&#8217;ai reporté <a href="http://bugs.nuitka.net/issue136">un bug</a> sur <a href="http://nuitka.net/">nuitka</a>, un compilateur Python.</p>
<p>Mon rapport était incomplet, et on m&#8217;a demandé plus d&#8217;informations. J&#8217;ai pris du temps, mais j&#8217;ai répondu. </p>
<p>Malheureusement à la deuxième demande d&#8217;informations, j&#8217;ai trainé la patte. Je l&#8217;ai mis dans ma todo list, et ai regardé en chien de fusil l&#8217;entrée pendant des mois.</p>
<p>Il fallait réinstaller nuitka, me replonger dans ce que je voulais faire à l&#8217;époque, lancer la compilation, répondre sur le bug tracker. Une heure dépensée au moins.</p>
<p>C&#8217;est ça dont les gens ne se rendent pas compte : participer à l&#8217;open source, ou à un quelconque effort collectif, ça prend énormément de temps. Entre les interruptions que ça génère, l&#8217;historique qu&#8217;il faut remonter à chaque fois, le changement de contexte, et bien entendu l&#8217;activité elle-même.</p>
<p>Donc, quand on vous rapporte un bug, même de manière énervée, bénissez le Dieu de la procrastination que la personne ait pris le temps de le faire. Vous ne vous devez rien l&#8217;un à l&#8217;autre, et c&#8217;est un beau moment de synergie humaine.</p>
<p>En l’occurrence, donc, mon interlocuteur a fini par marquer le bug comme &#8220;lack of feedback&#8221;.</p>
<p>D&#8217;un certain côté, ça m&#8217;a soulagé, je n&#8217;avais plus du tout envie de m&#8217;y remettre.</p>
<p>D&#8217;un autre côté, j&#8217;ai culpabilisé, me disant que quand même, j&#8217;utilise du FOSS, faudrait contribuer plus, et que j&#8217;avais fais perdre du temps à l&#8217;auteur.</p>
<p>Au final, cette semaine, je reçois une notification comme quoi une autre personne a continué le fil : il a le même problème.</p>
<p>J&#8217;avais oublié ce détail : en prenant le temps d&#8217;ouvrir un fil de discussion, je lui avais donné vie. Je lui avait donné une légitimité. Et il se trouve qu&#8217;avec les infos fournies par le nouvel arrivant, le ticket a été marqué en bug, et sera corrigé.</p>
<p>C&#8217;est un effort collectif, et même si je n&#8217;ai pas fais autant que ce que j&#8217;aurais voulu, j&#8217;ai joué mon rôle. Un rôle imparfait, mais utile.</p>
<p>Donc souvenez-vous : reportez vos bugs, il en restera toujours quelque chose.</p>


feed_id: http://sametmax.com/?p=16009
title: Vrac Python (encore) 5
uri: Vrac-Python-(encore)-4-Recently-updated
url: http://sametmax.com/vrac-python-encore/
content:
<p>Les billets en vrac sont au blogging ce que les pâtes de fond de frigo sont à la cuisine: le dernier recours en cas de manque de ressources ou d&#8217;inspiration.</p>
<p>Mais bizarrement, c&#8217;est aussi quelque chose qui plait beaucoup. C&#8217;est d&#8217;ailleurs les posts que je préférais sur le standblog, ou les trucs qui énervaient sebsauvage avant qu&#8217;il shaarlise tout ça.</p>
<p>Bref, quelques trucs en Python qui peuvent être passés sous le radar.</p>
<h2>Min et Max ont un param &#8220;key&#8221;</h2>
<p>Si vous avez lu <a href="http://sametmax.com/ordonner-en-python/">l&#8217;article sur le tri</a>, vous savez que <code>sorted()</code> et <code>sort()</code> peuvent prendre une fonction de callback via l&#8217;argument <code>key</code>, permettant de choisir comment extraire l&#8217;information qui va servir à déterminer la place de chaque élément.</p>
<p><code>min</code> et <code>max</code> marchent de la même manière :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> scores <span style="color: #66cc66;">=</span> <span style="color: black;">&#123;</span><span style="color: #483d8b;">&quot;allemagne&quot;</span>: <span style="color: #ff4500;">1</span><span style="color: #66cc66;">,</span><span style="color: #483d8b;">&quot;montagne&quot;</span>: <span style="color: #ff4500;">0</span><span style="color: black;">&#125;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> scores.<span style="color: black;">items</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
dict_items<span style="color: black;">&#40;</span><span style="color: black;">&#91;</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'allemagne'</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span> <span style="color: black;">&#40;</span><span style="color: #483d8b;">'montagne'</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #008000;">max</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: black;">&#40;</span><span style="color: #483d8b;">'montagne'</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #008000;">max</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: #66cc66;">,</span> key<span style="color: #66cc66;">=</span><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: black;">&#40;</span><span style="color: #483d8b;">'allemagne'</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<h2><code>next</code> possède un second paramètre</h2>
<p>Vous savez, sur les dicos, on peut choper une valeur par défaut si une clé n&#8217;existe pas :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> scores.<span style="color: black;">get</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;allemagne&quot;</span><span style="color: black;">&#41;</span>
<span style="color: #ff4500;">1</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> scores.<span style="color: black;">get</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;kamoulox&quot;</span><span style="color: #66cc66;">,</span> 1j<span style="color: black;">&#41;</span>
1j</pre></td></tr></table></div>

<p>Mais ceci n&#8217;existe pas pour les listes. Je pensais que c&#8217;était un oubli, mais en fait c&#8217;est comblé par le deuxième argument de <code>next</code> :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> l <span style="color: #66cc66;">=</span> <span style="color: #008000;">list</span><span style="color: black;">&#40;</span><span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> l
<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> g <span style="color: #66cc66;">=</span> <span style="color: #008000;">iter</span><span style="color: black;">&#40;</span>l<span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> next<span style="color: black;">&#40;</span>g<span style="color: #66cc66;">,</span> 1j<span style="color: black;">&#41;</span>
<span style="color: #ff4500;">0</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> next<span style="color: black;">&#40;</span>g<span style="color: #66cc66;">,</span> 1j<span style="color: black;">&#41;</span>
1j</pre></td></tr></table></div>

<h2><code>__future__</code> n&#8217;est pas bullet proof</h2>
<p>Certains comportements backportés en Python 2.7 ne peuvent pas être parfaitement implémentés. Ce sont &#8220;ce qu&#8217;on peut avoir de plus proche&#8221;. C&#8217;est déjà pas mal, et je les active tout le temps, mais ça peut vous rattraper à un moment inattendu.</p>
<p>Par exemple, les caractères d&#8217;échappements unicodes.</p>
<p>En Python 3:</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> r<span style="color: #483d8b;">&quot;<span style="color: #000099; font-weight: bold;">\u</span>&quot;</span>
<span style="color: #483d8b;">'<span style="color: #000099; font-weight: bold;">\\</span>u'</span></pre></td></tr></table></div>

<p>En Python 2.7, par contre, utiliser <code>u</code> et <code>r</code> entraine une exception :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> ur<span style="color: #483d8b;">&quot;<span style="color: #000099; font-weight: bold;">\u</span>&quot;</span>
  File <span style="color: #483d8b;">&quot;&lt;stdin&gt;&quot;</span><span style="color: #66cc66;">,</span> line <span style="color: #ff4500;">1</span>
<span style="color: #008000;">SyntaxError</span>: <span style="color: black;">&#40;</span><span style="color: #008000;">unicode</span> error<span style="color: black;">&#41;</span> <span style="color: #483d8b;">'rawunicodeescape'</span> codec can<span style="color: #483d8b;">'t decode bytes in position 0-1: truncated <span style="color: #000099; font-weight: bold;">\u</span>XXXX</span></pre></td></tr></table></div>

<p>Et donc si on active les littéraux unicodes (ce qui est une bonne pratique) :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> r<span style="color: #483d8b;">&quot;<span style="color: #000099; font-weight: bold;">\u</span>&quot;</span>
  File <span style="color: #483d8b;">&quot;&lt;stdin&gt;&quot;</span><span style="color: #66cc66;">,</span> line <span style="color: #ff4500;">1</span>
<span style="color: #008000;">SyntaxError</span>: <span style="color: black;">&#40;</span><span style="color: #008000;">unicode</span> error<span style="color: black;">&#41;</span> <span style="color: #483d8b;">'rawunicodeescape'</span> codec can<span style="color: #483d8b;">'t decode bytes in position 0-1: truncated <span style="color: #000099; font-weight: bold;">\u</span>XXXX</span></pre></td></tr></table></div>

<p>De quoi se gratter la tête sur des regexs ou des chemins de fichiers Windows.</p>


feed_id: http://sametmax.com/?p=16016
title: Comment installer des libs Python externes dans QGIS ? 5
uri: Comment-installer-des-libs-Python-externes-dans-QGIS-3-Recently-u
url: http://sametmax.com/comment-installer-des-libs-externes-dans-qgis/
content:
<p>QGIS vient avec son Python perso, séparé du reste du système. Du coup si vous faites un <code>pip install une_lib</code>, elle s&#8217;installera sur le Python du système, et non de QGIS. Si vous voulez utiliser <code>requests</code> ou <code>arrow</code> pour vos scripts, c&#8217;est relou, il faut les télécharger, les extraire, et les mettre à la main sur le <code>PYTHONPATH</code>.</p>
<p>Il est pourtant possible de manipuler interpréteur Python de QGIS, c&#8217;est juste que ça saute pas aux yeux :) Ca va nous permettre d&#8217;installer pip (si ça ne vous parle par, on a <a href="http://sametmax.com/votre-python-aime-les-pip/">un article</a> pour ça), à la mano, à l&#8217;ancienne, comme un homme qui fait ses cartes à la main sur des calques avec des lames de rasoirs en guise de gomme.</p>
<p>D&#8217;abord, trouver où il est niché. Sur ma machine, il est dans &#8220;C:\Program Files\QGIS Wien\bin\python.exe&#8221;.</p>
<p>Si vous le démarrer, vous noterez qu&#8217;il plante en prétextant qu&#8217;il ne trouve pas le module <code>site</code>. Il faut donc lui dire où sont installées les libs en faisant:</p>
<p><code>set PYTHONHOME=chemin vers l'installation de Python de QGIS.</code></p>
<p>Chez moi ça donne :</p>
<p><code>set PYTHONHOME=C:\Program Files\QGIS Wien\apps\Python27\</code></p>
<p>Ainsi vous pouvez lancer <code>C:\Program Files\QGIS Wien\bin\python.exe</code> dans la console et obtenir le shell Python de QGIS.</p>
<p>Ensuite, il faut télécharger <a href="https://bootstrap.pypa.io/ez_setup.py">ez_tools.py</a> qui va nous servir à installer setuptools dans le Python voulu. C&#8217;est un script Python (meta meta ! \^O^\), qu&#8217;on lance avec l&#8217;interpréteur qui nous intéresse, dans mon cas:</p>
<p><code>"C:\Program Files\QGIS Wien\bin\python.exe" C:\Users\sam\Downloads\ez_setup.py</code></p>
<p>Il va télécharger depuis internet tout un tas de trucs, et installer tout un tas de machins. Parfois, ça va râler parce que vous n&#8217;avez pas les droits. Dans ce cas, lancez la console en mode admin, et faites un <code>cd</code> sur le bureau avant de lancer la commande.</p>
<p>Bien, on a setuptools, qui a du rajouter la commande <code>easy_install</code>. Chez moi elle est dans &#8220;C:\Program Files\QGIS Wien\apps\Python27\Scripts&#8221;.</p>
<p>On va s&#8217;en servir pour installer <code>pip</code>.</p>
<p>Que de bordel !</p>
<p><code>C:\Program Files\QGIS Wien\apps\Python27\Scripts\easy_install.exe pip </code></p>
<p>Ca remouline, ça re-dl.</p>
<p>Ce qui va nous mettre la comamnde <code>pip</code> dans le même dossier qu&#8217;<code>easy_install</code>.</p>
<p>Et pouf, en utilisant le chemin canonique, on peut utiliser <code>pip</code> :</p>
<p><code>C:\Program Files\QGIS Wien\apps\Python27\Scripts\pip install ipython pyrealine</code></p>
<p>Faites attention néanmoins, utiliser cet interpréteur hors de QGIS ne vous donne pas accès à des objets comme <code>iface</code> qui n&#8217;existent que quand l&#8217;UI de QGIS est chargée. Ca reste pratique pour installer des libs externes, faire des tests python rapides dans le même environnement que QGIS sans lancer tout le bouzin et se la péter face à ses collègues géomaticiens qui ont l&#8217;air d&#8217;une poule avec un canif devant une console.</p>


feed_id: http://sametmax.com/?p=16027
title: Revue de code publique 17
uri: Revue-de-code-publique-1
url: http://sametmax.com/revue-de-code-publique/
content:
<p>En faisant ma revue quotidienne, je suis tombé sur <a href="https://twitter.com/NicolasDiNunno/status/584825847925846016/photo/1">un code Python assez tarabiscoté</a> que twitter s&#8217;est empressé de massacrer.</p>
<p>Néanmoins je ne pense pas que mettre l&#8217;affiche à l&#8217;auteur soit le meilleur moyen de l&#8217;amener à passer plus de temps à coder en Python et à participer à la communauté.</p>
<p>En effet, il me semble qu&#8217;il est prof de bio (si j&#8217;ai bien suivi l&#8217;histo), et personnellement, si on devait me demander de faire un  schéma d&#8217;une méiose, je pense que le résultat serait du même niveau.</p>
<p>D&#8217;un autre côté laisser circuler une code dans ce format, surtout si il a une vocation pédagogique serait contre productif. Améliorons donc ce code pas à pas en justifiant des modifications.</p>
<p>D&#8217;abord, voici la fonction en question :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> tripositions<span style="color: black;">&#40;</span>Ligne<span style="color: black;">&#41;</span>: <span style="color: #808080; font-style: italic;">#Tri a bulle ?</span>
    l <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span>k <span style="color: #ff7700;font-weight:bold;">for</span> k <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #008000;">len</span><span style="color: black;">&#40;</span>Ligne<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span>
    q <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span>Ligne<span style="color: #66cc66;">,</span> l<span style="color: black;">&#93;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #008000;">len</span><span style="color: black;">&#40;</span>Ligne<span style="color: black;">&#41;</span>-<span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">for</span> j <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #008000;">len</span><span style="color: black;">&#40;</span>Ligne<span style="color: black;">&#41;</span>-i-<span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>:
            <span style="color: #ff7700;font-weight:bold;">if</span> q<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span><span style="color: black;">&#91;</span>j<span style="color: black;">&#93;</span><span style="color: #66cc66;">&gt;</span>q<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span><span style="color: black;">&#91;</span>j+<span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span>:
                <span style="color: #ff7700;font-weight:bold;">for</span> k <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span>:
                    q<span style="color: black;">&#91;</span>k<span style="color: black;">&#93;</span><span style="color: black;">&#91;</span>j<span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span> q<span style="color: black;">&#91;</span>k<span style="color: black;">&#93;</span><span style="color: black;">&#91;</span>j+<span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span><span style="color: #66cc66;">=</span>q<span style="color: black;">&#91;</span>k<span style="color: black;">&#93;</span><span style="color: black;">&#91;</span>j+<span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span> q<span style="color: black;">&#91;</span>k<span style="color: black;">&#93;</span><span style="color: black;">&#91;</span>j<span style="color: black;">&#93;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">while</span> q<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span><span style="color: #66cc66;">==</span><span style="color: #ff4500;">0</span>:
        q<span style="color: #66cc66;">=</span><span style="color: black;">&#91;</span><span style="color: black;">&#91;</span>q<span style="color: black;">&#91;</span>i<span style="color: black;">&#93;</span><span style="color: black;">&#91;</span>j<span style="color: black;">&#93;</span> <span style="color: #ff7700;font-weight:bold;">for</span> j <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span><span style="color: #66cc66;">,</span> <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>q<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span> <span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">return</span><span style="color: black;">&#40;</span>q<span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Elle effectue un bubble sort (un tri des éléments en faisant remonter les plus grands en fin de liste, comme des bulles), puis retire les zéros, et retourne deux ensembles : une liste des éléments triés, et une liste de la position des ces éléments dans la liste originale. Par exemple:</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> tripositions<span style="color: black;">&#40;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">4</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">0</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">9</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">0</span><span style="color: #66cc66;">,</span>  <span style="color: #ff4500;">5</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">17</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">7</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
<span style="color: black;">&#91;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">4</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">5</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">7</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">9</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">17</span><span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span> <span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">4</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">6</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">2</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">5</span><span style="color: black;">&#93;</span><span style="color: black;">&#93;</span></pre></td></tr></table></div>

<p>D&#8217;abord, essayons de comprendre le fonctionnement de l&#8217;algo :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> tripositions<span style="color: black;">&#40;</span>Ligne<span style="color: black;">&#41;</span>: <span style="color: #808080; font-style: italic;">#Tri a bulle ?</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Ici on récupère une liste [0, 1, 2, 3...] qui contient les positions</span>
    <span style="color: #808080; font-style: italic;"># des éléments dans la liste passée en paramètre</span>
    l <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span>k <span style="color: #ff7700;font-weight:bold;">for</span> k <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #008000;">len</span><span style="color: black;">&#40;</span>Ligne<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span>
    <span style="color: #808080; font-style: italic;"># Là on groupe la liste initiale et les positions en une liste</span>
    q <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span>Ligne<span style="color: #66cc66;">,</span> l<span style="color: black;">&#93;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># On fait un tour de boucle pour chaque élément de la liste</span>
    <span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #008000;">len</span><span style="color: black;">&#40;</span>Ligne<span style="color: black;">&#41;</span>-<span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>:
        <span style="color: #808080; font-style: italic;"># Et à chaque tout de boucle, on refait une boucle qui fait elle-même</span>
        <span style="color: #808080; font-style: italic;"># un tour de boucle pour tous les éléments de la liste, sauf le dernier</span>
        <span style="color: #ff7700;font-weight:bold;">for</span> j <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #008000;">len</span><span style="color: black;">&#40;</span>Ligne<span style="color: black;">&#41;</span>-i-<span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>:
            <span style="color: #808080; font-style: italic;"># Si l'élément de la liste à la position actuelle est plus grand</span>
            <span style="color: #808080; font-style: italic;"># que l'élément de la liste à la prochaine position</span>
            <span style="color: #ff7700;font-weight:bold;">if</span> q<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span><span style="color: black;">&#91;</span>j<span style="color: black;">&#93;</span><span style="color: #66cc66;">&gt;</span>q<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span><span style="color: black;">&#91;</span>j+<span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span>:
                <span style="color: #808080; font-style: italic;"># On change la place de cet élément dans la liste initiale,</span>
                <span style="color: #808080; font-style: italic;"># la place de la position de cet élément dans la liste des</span>
                <span style="color: #808080; font-style: italic;"># positions</span>
                <span style="color: #ff7700;font-weight:bold;">for</span> k <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span>:
                    q<span style="color: black;">&#91;</span>k<span style="color: black;">&#93;</span><span style="color: black;">&#91;</span>j<span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span> q<span style="color: black;">&#91;</span>k<span style="color: black;">&#93;</span><span style="color: black;">&#91;</span>j+<span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span><span style="color: #66cc66;">=</span>q<span style="color: black;">&#91;</span>k<span style="color: black;">&#93;</span><span style="color: black;">&#91;</span>j+<span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span> q<span style="color: black;">&#91;</span>k<span style="color: black;">&#93;</span><span style="color: black;">&#91;</span>j<span style="color: black;">&#93;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Maintenant que tout est trié, si il y a des zéro, il sont tous en début</span>
    <span style="color: #808080; font-style: italic;"># de liste. Tant qu'il y a un zéro en début de liste, on retire le premier</span>
    <span style="color: #808080; font-style: italic;"># élément de la liste initiale et de la liste des positions.</span>
    <span style="color: #ff7700;font-weight:bold;">while</span> q<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span><span style="color: #66cc66;">==</span><span style="color: #ff4500;">0</span>:
        q<span style="color: #66cc66;">=</span><span style="color: black;">&#91;</span><span style="color: black;">&#91;</span>q<span style="color: black;">&#91;</span>i<span style="color: black;">&#93;</span><span style="color: black;">&#91;</span>j<span style="color: black;">&#93;</span> <span style="color: #ff7700;font-weight:bold;">for</span> j <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span><span style="color: #66cc66;">,</span> <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>q<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span> <span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">return</span><span style="color: black;">&#40;</span>q<span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Le style d&#8217;écriture en Python étant codifié par un document appelé le <a href="http://sametmax.com/le-pep8-en-resume/">PEP8</a>, reformatons le code afin qu&#8217;il soit plus facile à lire :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># Les noms des variables ne commencent pas par une majuscule. On réservera</span>
<span style="color: #808080; font-style: italic;"># les majuscules aux noms de classe.</span>
<span style="color: #808080; font-style: italic;"># On donne aussi un nom un peu plus explicite à la fonction</span>
<span style="color: #ff7700;font-weight:bold;">def</span> elements_tries_et_positions<span style="color: black;">&#40;</span>ligne<span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot; Tri a bulle d'une liste retournant les valeurs triés et leurs positions&quot;&quot;&quot;</span>
    <span style="color: #808080; font-style: italic;"># On met une doctstring pour documenter la fonction plutôt qu'un commentaire</span>
    <span style="color: #808080; font-style: italic;"># On pourra ainsi appeler help(elements_tries_et_positions)</span>
&nbsp;
    l <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span>k <span style="color: #ff7700;font-weight:bold;">for</span> k <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #008000;">len</span><span style="color: black;">&#40;</span>ligne<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span>
    q <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span>ligne<span style="color: #66cc66;">,</span> l<span style="color: black;">&#93;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># On aère un peu le code en rajoutant des espaces autour des signes = et &lt;</span>
    <span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #008000;">len</span><span style="color: black;">&#40;</span>ligne<span style="color: black;">&#41;</span>-<span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">for</span> j <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #008000;">len</span><span style="color: black;">&#40;</span>ligne<span style="color: black;">&#41;</span>-i-<span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>:
            <span style="color: #ff7700;font-weight:bold;">if</span> q<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span><span style="color: black;">&#91;</span>j<span style="color: black;">&#93;</span> <span style="color: #66cc66;">&gt;</span> q<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span><span style="color: black;">&#91;</span>j+<span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span>:
                <span style="color: #ff7700;font-weight:bold;">for</span> k <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span>:
                    q<span style="color: black;">&#91;</span>k<span style="color: black;">&#93;</span><span style="color: black;">&#91;</span>j<span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span> q<span style="color: black;">&#91;</span>k<span style="color: black;">&#93;</span><span style="color: black;">&#91;</span>j+<span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span> <span style="color: #66cc66;">=</span> q<span style="color: black;">&#91;</span>k<span style="color: black;">&#93;</span><span style="color: black;">&#91;</span>j+<span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span> q<span style="color: black;">&#91;</span>k<span style="color: black;">&#93;</span><span style="color: black;">&#91;</span>j<span style="color: black;">&#93;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">while</span> q<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span> <span style="color: #66cc66;">==</span> <span style="color: #ff4500;">0</span>:
        q <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span><span style="color: black;">&#91;</span>q<span style="color: black;">&#91;</span>i<span style="color: black;">&#93;</span><span style="color: black;">&#91;</span>j<span style="color: black;">&#93;</span> <span style="color: #ff7700;font-weight:bold;">for</span> j <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span><span style="color: #66cc66;">,</span> <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>q<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span> <span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># &quot;return&quot; est un mot clé, pas une fonction, et n'a pas besoin de</span>
    <span style="color: #808080; font-style: italic;"># parenthèses</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> q</pre></td></tr></table></div>

<p>Le code utilise massivement des <code>ranges()</code> et <code>len()</code>, ce qui me laisse à penser que notre auteur a voulu reproduire un schéma qu&#8217;il a connu lors d&#8217;une expérience dans un autre langage tel que le C ou le Fortran. C&#8217;est très courant quand on passe à une nouvelle technologie, car on essaye de trouver ses repères.</p>
<p>Premier passage pour retirer quelques appels qui ne sont pas idiomatiques :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> elements_tries_et_positions<span style="color: black;">&#40;</span>ligne<span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot; Tri a bulle d'une liste retournant les valeurs triés et leurs positions&quot;&quot;&quot;</span>
    <span style="color: #808080; font-style: italic;"># range() va déjà retourner un itérable contenant les valeurs voulues donc</span>
    <span style="color: #808080; font-style: italic;"># pas besoin de faire une liste en intension dessus</span>
    q <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span>ligne<span style="color: #66cc66;">,</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #008000;">len</span><span style="color: black;">&#40;</span>ligne<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Il n'y a pas d'avantage de performance à itérer sur range() plutôt que</span>
    <span style="color: #808080; font-style: italic;"># sur &quot;ligne&quot; directement : c'est toujours une itération </span>
    <span style="color: #808080; font-style: italic;"># de même taille et seul le nombre de tours nous intéresse</span>
    <span style="color: #808080; font-style: italic;"># puisqu'on utilise pas l'index dans notre code</span>
    <span style="color: #ff7700;font-weight:bold;">for</span> e1 <span style="color: #ff7700;font-weight:bold;">in</span> ligne:
        <span style="color: #808080; font-style: italic;"># enumerate() retourne automatiquement un itérable [(index, element),</span>
        <span style="color: #808080; font-style: italic;"># (index, element), ...], et permet de se passer du calcule manuel</span>
        <span style="color: #808080; font-style: italic;"># de la position des éléments</span>
        <span style="color: #808080; font-style: italic;"># ligne[:-1] est ce qu'on appelle un slicing, qui nous permet de</span>
        <span style="color: #808080; font-style: italic;"># créer une copie de la liste sans le dernier élément.</span>
        <span style="color: #ff7700;font-weight:bold;">for</span> j<span style="color: #66cc66;">,</span> e2 <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">enumerate</span><span style="color: black;">&#40;</span>ligne<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: #808080; font-style: italic;"># q[0] est la même chose que &quot;ligne&quot;, donc pas besoin de faire</span>
            <span style="color: #808080; font-style: italic;"># un indexing.</span>
            <span style="color: #ff7700;font-weight:bold;">if</span> ligne<span style="color: black;">&#91;</span>j<span style="color: black;">&#93;</span> <span style="color: #66cc66;">&gt;</span> ligne<span style="color: black;">&#91;</span>j+<span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span>:
                <span style="color: #ff7700;font-weight:bold;">for</span> k <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>:
                    q<span style="color: black;">&#91;</span>k<span style="color: black;">&#93;</span><span style="color: black;">&#91;</span>j<span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span> q<span style="color: black;">&#91;</span>k<span style="color: black;">&#93;</span><span style="color: black;">&#91;</span>j+<span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span> <span style="color: #66cc66;">=</span> q<span style="color: black;">&#91;</span>k<span style="color: black;">&#93;</span><span style="color: black;">&#91;</span>j+<span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span> q<span style="color: black;">&#91;</span>k<span style="color: black;">&#93;</span><span style="color: black;">&#91;</span>j<span style="color: black;">&#93;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Même chose puisque q[0] == ligne</span>
    <span style="color: #ff7700;font-weight:bold;">while</span> ligne<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span> <span style="color: #66cc66;">==</span> <span style="color: #ff4500;">0</span>:
        q <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span><span style="color: black;">&#91;</span>q<span style="color: black;">&#91;</span>i<span style="color: black;">&#93;</span><span style="color: black;">&#91;</span>j<span style="color: black;">&#93;</span> <span style="color: #ff7700;font-weight:bold;">for</span> j <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span><span style="color: #66cc66;">,</span> <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>q<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span> <span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">return</span> q</pre></td></tr></table></div>

<p>Le fait de manipuler la liste initiale et la liste d&#8217;indexes groupés dans une 3eme liste rend le code plus difficile à lire. Nous allons éviter ça en créant la liste finale à la fin.</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> elements_tries_et_positions<span style="color: black;">&#40;</span>ligne<span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot; Tri a bulle d'une liste retournant les valeurs triés et leurs positions&quot;&quot;&quot;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># On supprime la création de la liste finale et on manipule</span>
    <span style="color: #808080; font-style: italic;"># deux variables pendant toute la fonction ce qui rend plus clair sur</span>
    <span style="color: #808080; font-style: italic;"># quelle partie des données on travaille.</span>
    positions <span style="color: #66cc66;">=</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #008000;">len</span><span style="color: black;">&#40;</span>ligne<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">for</span> e1 <span style="color: #ff7700;font-weight:bold;">in</span> ligne:
        <span style="color: #ff7700;font-weight:bold;">for</span> j<span style="color: #66cc66;">,</span> e2 <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">enumerate</span><span style="color: black;">&#40;</span>ligne<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: #808080; font-style: italic;"># On a déjà e2 gratuitement, pas besoin d'utiliser un index</span>
            <span style="color: #ff7700;font-weight:bold;">if</span> e2 <span style="color: #66cc66;">&gt;</span> ligne<span style="color: black;">&#91;</span>j+<span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span>:
                <span style="color: #808080; font-style: italic;"># Ici, on manipules les listes par leur nom, c'est</span>
                <span style="color: #808080; font-style: italic;"># plus facile à comprendre que des indexes</span>
                ligne<span style="color: black;">&#91;</span>j<span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span> ligne<span style="color: black;">&#91;</span>j+<span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span> <span style="color: #66cc66;">=</span> ligne<span style="color: black;">&#91;</span>j+<span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span> ligne<span style="color: black;">&#91;</span>j<span style="color: black;">&#93;</span>
                positions<span style="color: black;">&#91;</span>j<span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span> positions<span style="color: black;">&#91;</span>j+<span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span> <span style="color: #66cc66;">=</span> positions<span style="color: black;">&#91;</span>j+<span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span> positions<span style="color: black;">&#91;</span>j<span style="color: black;">&#93;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Si ligne[0] == 0, alors bool(ligne(0)) == False. Python n'a pas besoin</span>
    <span style="color: #808080; font-style: italic;"># de la comparaison numérique dans une condition, juste du contexte booléen.</span>
    <span style="color: #808080; font-style: italic;"># En l'écrivant ainsi, on se rapproche du langage parlé.</span>
    <span style="color: #ff7700;font-weight:bold;">while</span> <span style="color: #ff7700;font-weight:bold;">not</span> ligne<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span>:
        <span style="color: #808080; font-style: italic;"># Encore une fois, inutile de grouper les deux variables dans une</span>
        <span style="color: #808080; font-style: italic;"># liste. Les séparer rend l'action plus lisible.</span>
        ligne <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span>ligne<span style="color: black;">&#91;</span>i<span style="color: black;">&#93;</span> <span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span><span style="color: #66cc66;">,</span> <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>ligne<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span>
        positions <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span>positions<span style="color: black;">&#91;</span>i<span style="color: black;">&#93;</span> <span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span><span style="color: #66cc66;">,</span> <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>ligne<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># On retourne les deux variables sous forme de liste à la fin</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: black;">&#91;</span>ligne<span style="color: #66cc66;">,</span> positions<span style="color: black;">&#93;</span></pre></td></tr></table></div>

<p>Enfin, et meme si les listes en intension sont une fonctionalité du langage qu&#8217;il faut toujours garder sous le code, ce sont des boucles et il est bon de se passer de boucles non nécessaires. A l&#8217;inverse, la compatibilité avec Python 3 va nous obliger à rajouter une boucle (implicite) de plus.</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> elements_tries_et_positions<span style="color: black;">&#40;</span>ligne<span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot; Tri a bulle d'une liste retournant les valeurs triés et leurs positions&quot;&quot;&quot;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># range() retourne un générateur en Python 3, il faut donc le convertir</span>
    <span style="color: #808080; font-style: italic;"># en liste pour que ça marche dans les 2 versions</span>
    positions <span style="color: #66cc66;">=</span> <span style="color: #008000;">list</span><span style="color: black;">&#40;</span><span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #008000;">len</span><span style="color: black;">&#40;</span>ligne<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">for</span> e1 <span style="color: #ff7700;font-weight:bold;">in</span> ligne:
        <span style="color: #ff7700;font-weight:bold;">for</span> j<span style="color: #66cc66;">,</span> e2 <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">enumerate</span><span style="color: black;">&#40;</span>ligne<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;">if</span> e2 <span style="color: #66cc66;">&gt;</span> ligne<span style="color: black;">&#91;</span>j+<span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span>:
                ligne<span style="color: black;">&#91;</span>j<span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span> ligne<span style="color: black;">&#91;</span>j+<span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span> <span style="color: #66cc66;">=</span> ligne<span style="color: black;">&#91;</span>j+<span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span> ligne<span style="color: black;">&#91;</span>j<span style="color: black;">&#93;</span>
                positions<span style="color: black;">&#91;</span>j<span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span> positions<span style="color: black;">&#91;</span>j+<span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span> <span style="color: #66cc66;">=</span> positions<span style="color: black;">&#91;</span>j+<span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span> positions<span style="color: black;">&#91;</span>j<span style="color: black;">&#93;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">while</span> <span style="color: #ff7700;font-weight:bold;">not</span> ligne<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span>:
        <span style="color: #808080; font-style: italic;"># Il s'agit juste de retirer tous les éléments nuls de gauche, il</span>
        <span style="color: #808080; font-style: italic;"># n'est pas nécessaire de parcourir toute la liste pour ça : pop(0)</span>
        <span style="color: #808080; font-style: italic;"># retire l'élément en début de liste</span>
        ligne.<span style="color: black;">pop</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>
        positions.<span style="color: black;">pop</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;">return</span> <span style="color: black;">&#91;</span>ligne<span style="color: #66cc66;">,</span> positions<span style="color: black;">&#93;</span></pre></td></tr></table></div>

<p>Rajoutons des commentaires techniques, car en première lecture, ce n&#8217;est pas évident de savoir quel bloc fait quoi (le retrait des zéros m&#8217;a demandé un certains temps avant que je le pige) :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> elements_tries_et_positions<span style="color: black;">&#40;</span>ligne<span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot; Tri a bulle d'une liste retournant les valeurs triés et leurs positions&quot;&quot;&quot;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Liste des positions initiales des éléments</span>
    positions <span style="color: #66cc66;">=</span> <span style="color: #008000;">list</span><span style="color: black;">&#40;</span><span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #008000;">len</span><span style="color: black;">&#40;</span>ligne<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Bubble sort qui traite en parallèle les valeurs et leurs positions</span>
    <span style="color: #ff7700;font-weight:bold;">for</span> e1 <span style="color: #ff7700;font-weight:bold;">in</span> ligne:
        <span style="color: #ff7700;font-weight:bold;">for</span> j<span style="color: #66cc66;">,</span> e2 <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">enumerate</span><span style="color: black;">&#40;</span>ligne<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;">if</span> e2 <span style="color: #66cc66;">&gt;</span> ligne<span style="color: black;">&#91;</span>j+<span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span>:
                ligne<span style="color: black;">&#91;</span>j<span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span> ligne<span style="color: black;">&#91;</span>j+<span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span> <span style="color: #66cc66;">=</span> ligne<span style="color: black;">&#91;</span>j+<span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span> ligne<span style="color: black;">&#91;</span>j<span style="color: black;">&#93;</span>
                positions<span style="color: black;">&#91;</span>j<span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span> positions<span style="color: black;">&#91;</span>j+<span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span> <span style="color: #66cc66;">=</span> positions<span style="color: black;">&#91;</span>j+<span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span> positions<span style="color: black;">&#91;</span>j<span style="color: black;">&#93;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Retrait des zéro (qui après le tri sont tous en début de liste)</span>
    <span style="color: #ff7700;font-weight:bold;">while</span> <span style="color: #ff7700;font-weight:bold;">not</span> ligne<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span>:
        ligne.<span style="color: black;">pop</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>
        positions.<span style="color: black;">pop</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;">return</span> <span style="color: black;">&#91;</span>ligne<span style="color: #66cc66;">,</span> positions<span style="color: black;">&#93;</span></pre></td></tr></table></div>

<p>En tout nous avons fait plusieurs choses, qui sont presque toujours les mêmes étapes pour toute revue de code :</p>
<ul>
<li>Formater le code pour qu&#8217;il soit plus lisible.</li>
<li>Retirer des opérations non nécessaires.</li>
<li>Utiliser des noms plus explicites pour nos conteneurs.</li>
<li>Utiliser les fonctions déjà proposées par Python plutôt que faire les choses manuellement.</li>
</ul>
<p>Python est un langage de haut niveau, qui favorise la productivité et met l&#8217;accent sur la lisibilité. Aussi il est bon de tirer parti le maximum du langage pour avoir le code le plus facile à lire possible. Ne pas hésiter à avoir des noms longs, des opérations sur deux lignes, des usages d&#8217;outils tout faits, etc.</p>
<p>J&#8217;imagine que le but de l&#8217;exercice était de faire coder un tri à bulle, donc j&#8217;ai modifié le code précédent. Néanmoins Python propose déjà des fonctions qui font tout ça automatiquement, et voici ce pourrait donner la fonction si on devait l&#8217;écrire en tirant parti du toute la puissance du langage :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># On met tout en anglais et on change le nom de paramètre pour montrer</span>
<span style="color: #808080; font-style: italic;"># qu'on accepte n'importe quel itérable.</span>
<span style="color: #808080; font-style: italic;"># On rajoute aussi deux paramètres avec des valeurs saines par défaut mais</span>
<span style="color: #808080; font-style: italic;"># qui permettent d'orienter le tri différemment si on le souhaite.</span>
<span style="color: #ff7700;font-weight:bold;">def</span> get_sorted_items_and_positions<span style="color: black;">&#40;</span>iterable<span style="color: #66cc66;">,</span> key<span style="color: #66cc66;">=</span><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: #66cc66;">,</span> reverse<span style="color: #66cc66;">=</span><span style="color: #008000;">False</span><span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot; Sort an iterable and return a tuple (sorted_items, old_positions)&quot;&quot;&quot;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># On récupère la liste de tous les éléments non nuls et leur position</span>
    indexed_non_null_elements <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span><span style="color: black;">&#40;</span>i<span style="color: #66cc66;">,</span> e<span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">for</span> i<span style="color: #66cc66;">,</span> e <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">enumerate</span><span style="color: black;">&#40;</span>iterable<span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">if</span> e<span style="color: black;">&#93;</span>
    <span style="color: #808080; font-style: italic;"># On les tri avec un tim sort plutôt qu'un bubble sort</span>
    indexed_non_null_elements.<span style="color: black;">sort</span><span style="color: black;">&#40;</span>key<span style="color: #66cc66;">=</span>key<span style="color: #66cc66;">,</span> reverse<span style="color: #66cc66;">=</span>reverse<span style="color: black;">&#41;</span>
    <span style="color: #808080; font-style: italic;"># On sépare les indexes des élements avec une astuce de sioux</span>
    indexes<span style="color: #66cc66;">,</span> elements <span style="color: #66cc66;">=</span> <span style="color: #008000;">zip</span><span style="color: black;">&#40;</span>*indexed_non_null_elements<span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># On retourne généralement un tuple quand on a peu de valeurs à retourner</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> elements<span style="color: #66cc66;">,</span> indexes</pre></td></tr></table></div>

<p>La fonction va alors retourner un tuple de tuple au lieu d&#8217;une liste de liste, mais sinon fera les mêmes opérations :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> get_sorted_items_and_positions<span style="color: black;">&#40;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">4</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">0</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">9</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">0</span><span style="color: #66cc66;">,</span>  <span style="color: #ff4500;">5</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">17</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">7</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
<span style="color: black;">&#40;</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">4</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">5</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">7</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">9</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">17</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span> <span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">4</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">6</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">2</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">5</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Néanmoins elle aura le double avantage de fonctionner avec n&#8217;importe quel itérable (<code>get_sorted_items_and_positions</code> acceptera alors en paramètre une liste, mais aussi un tuple, un set ou même un fichier) mais aussi d&#8217;être beaucoup plus rapide puisque <code>sort()</code> est codé en C sous le capot.</p>
<p>Comme ai-je pondu cette fonction ?</p>
<p>D&#8217;abord, j&#8217;ai observé l&#8217;algorithme, et j&#8217;ai noté que les zéros étaient retirés. Il est souvent plus facile de filtrer ses données avant le traitement, donc je retire les 0 tout au début. Python est un fantastique langage pour tout ce qui est filtre, et on peut non seulement le faire en une ligne, mais indexer les éléments restant dans la foulée.</p>
<p>Ensuite, j&#8217;utilise la fonction de tri intégrée au langage, qui est un algo non seulement plus efficace que le bubble sort mais en prime est codé en C par les auteurs de Python, donc qui sera beaucoup plus performant. <a href="http://sametmax.com/ordonner-en-python/">La manière dont fonctionne le tri en Python</a> permet de trier mes paires (position, valeur) comme un seul élément, mais en fonction de la valeur uniquement. Un autre avantage, c&#8217;est que cette fonction permet de changer le type de tri (par exemple trier du plus grand au plus petit), et donc je peux exposer ces paramètres supplémentaires dans ma fonction pour laisser plus de control à l&#8217;utilisateur. Grâce aux valeurs par défaut, ce contrôle supplémentaire ne rend pas l&#8217;usage plus complexe, puisque l&#8217;utilisateur peu juste ignorer ces paramètres.</p>
<p>Enfin, j&#8217;utilise une combinaison de slicing, d&#8217;<a href="http://sametmax.com/quest-ce-que-lunpacking-en-python-et-a-quoi-ca-sert/">unpacking</a> (via l&#8217;opéateur splat <a href="http://sametmax.com/operateur-splat-ou-etoile-en-python/">l&#8217;opérateur splat</a>) et une particularité de la fonction <a href="https://docs.python.org/3/library/functions.html?highlight=zip#zip">zip()</a> qui permet de transposer un itérable de paires en deux itérables d&#8217;éléments seuls :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> paires <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">&quot;a&quot;</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span> <span style="color: black;">&#40;</span><span style="color: #ff4500;">2</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">&quot;b&quot;</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span> <span style="color: black;">&#40;</span><span style="color: #ff4500;">3</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">&quot;c&quot;</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;">zip</span><span style="color: black;">&#40;</span>*paires<span style="color: black;">&#41;</span>
<span style="color: black;">&#91;</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">2</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">3</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span> <span style="color: black;">&#40;</span><span style="color: #483d8b;">'a'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'b'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'c'</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> nombres<span style="color: #66cc66;">,</span> lettres <span style="color: #66cc66;">=</span> <span style="color: #008000;">zip</span><span style="color: black;">&#40;</span>*paires<span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> nombres
<span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">2</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">3</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> lettres
<span style="color: black;">&#40;</span><span style="color: #483d8b;">'a'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'b'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'c'</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Notez bien que personne ne demande à quelqu&#8217;un qui commence à toucher du Python de trouver ce code. C&#8217;est juste comme ça qu&#8217;on finit par le faire, à l&#8217;usage.</p>


feed_id: http://sametmax.com/?p=16039
title: Reformater son code avec yapf 16
uri: Reformater-son-code-avec-yapf-3
url: http://sametmax.com/reformater-son-code-avec-yapf/
content:
<p>En ce moment un outil fait son petit buzz sur hackernews, mais je n&#8217;en avais pas parlé jusqu&#8217;ici car il n&#8217;était pas encore uploadé sur pypi. C&#8217;est chose faite :</p>

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

<p>Yapf est un reformateur de code, vous lui filez un fichier (ou un dossier à parcourir récursivement), et il reformate le code pour qu&#8217;il soit plus lisible, et plus proche du <a href="http://sametmax.com/le-pep8-en-resume/">PEP8</a>.</p>
<p>On en parle en ce moment car le code appartient à Google et que le projet est comparé à <a href="http://golang.org/cmd/gofmt/">gofmt</a> le formatteur intégré à la stack Goland dont les Golois nous ventent les mérites avec moult regards condescendant vers tous les autres langages depuis qu&#8217;ils l&#8217;ont.</p>
<p>Yapf est loin des features de gofmt pour le moment, mais c&#8217;est cool d&#8217;avoir un point de départ, car c&#8217;est vrai que ça manquait. Non pas que ça n&#8217;existait pas déjà, mais les tentatives précédentes n&#8217;avaient soulevé aucun enthousiasme, et donc pas beaucoup de contrib. Il a fallut, comme d&#8217;hab, qu&#8217;un concours de celui qui a la plus grosse motive tout ça à coup d&#8217;éGOs, si vous voyez ce que je veux dire. On a bien eu pip intégré à Python parce que les codeurs JS se foutaient de notre gueule avec npm installé par défaut. </p>
<p>Bref, pour le moment yapf s&#8217;occupe surtout des espaces et de l&#8217;indentation, mais il le fait bien.</p>
<p>Soit le programme suivant :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">from</span> <span style="color: #dc143c;">__future__</span> <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: black;">&#40;</span>unicode_literals<span style="color: #66cc66;">,</span> absolute_import<span style="color: #66cc66;">,</span> print_function<span style="color: #66cc66;">,</span>
    division<span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> yolo<span style="color: black;">&#40;</span>a<span style="color: #66cc66;">,</span>b <span style="color: #66cc66;">=</span><span style="color: #008000;">None</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;">&quot;Ca fait mal aux yeux hein ?&quot;</span><span style="color: black;">&#41;</span>
&nbsp;
        a<span style="color: #66cc66;">=</span> <span style="color: #ff4500;">1</span>
&nbsp;
        <span style="color: #ff7700;font-weight:bold;">if</span> a<span style="color: #66cc66;">==</span>b :
            <span style="color: #ff7700;font-weight:bold;">return</span><span style="color: black;">&#40;</span>b<span style="color: black;">&#41;</span>
&nbsp;
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">True</span> <span style="color: #ff7700;font-weight:bold;">and</span>      <span style="color: #008000;">False</span>:<span style="color: #808080; font-style: italic;"># c'est chiant n'est-il pas ?</span>
          <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #483d8b;">&quot;bob&quot;</span>
&nbsp;
&nbsp;
&nbsp;
    WOLOLO <span style="color: #66cc66;">=</span> <span style="color: black;">&#123;</span>
        <span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">2</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">3</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">4</span><span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span>
        <span style="color: black;">&#91;</span><span style="color: #ff4500;">5</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">6</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">7</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">8</span><span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span>
        <span style="color: black;">&#91;</span><span style="color: #ff4500;">9</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">10</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">11</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">12</span><span style="color: black;">&#93;</span>
    <span style="color: black;">&#125;</span>
&nbsp;
    OYOOYO <span style="color: #66cc66;">=</span> <span style="color: black;">&#123;</span>
        <span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">2</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">3</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">4</span><span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span>
        <span style="color: black;">&#91;</span><span style="color: #ff4500;">5</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">6</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">7</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">8</span><span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span>
        <span style="color: black;">&#91;</span><span style="color: #ff4500;">9</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">10</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">11</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">12</span><span style="color: black;">&#93;</span>
    <span style="color: black;">&#125;</span>  <span style="color: #808080; font-style: italic;"># yapf: disable</span></pre></td></tr></table></div>

<p>Un petit coup de :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="bash" style="font-family:monospace;">yapf programme.py</pre></td></tr></table></div>

<p>Et pouf, il vous sort :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">from</span> <span style="color: #dc143c;">__future__</span> <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: black;">&#40;</span>unicode_literals<span style="color: #66cc66;">,</span> absolute_import<span style="color: #66cc66;">,</span> print_function<span style="color: #66cc66;">,</span>
                        division<span style="color: black;">&#41;</span>
&nbsp;
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> yolo<span style="color: black;">&#40;</span>a<span style="color: #66cc66;">,</span> b<span style="color: #66cc66;">=</span><span style="color: #008000;">None</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;">&quot;Ca fait mal aux yeux hein ?&quot;</span><span style="color: black;">&#41;</span>
&nbsp;
  a <span style="color: #66cc66;">=</span> <span style="color: #ff4500;">1</span>
&nbsp;
  <span style="color: #ff7700;font-weight:bold;">if</span> a <span style="color: #66cc66;">==</span> b:
    <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: black;">&#40;</span>b<span style="color: black;">&#41;</span>
&nbsp;
  <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">True</span> <span style="color: #ff7700;font-weight:bold;">and</span> <span style="color: #008000;">False</span>:  <span style="color: #808080; font-style: italic;"># c'est chiant n'est-il pas ?</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #483d8b;">&quot;bob&quot;</span>
&nbsp;
&nbsp;
WOLOLO <span style="color: #66cc66;">=</span> <span style="color: black;">&#123;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">2</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">3</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">4</span><span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span> <span style="color: black;">&#91;</span><span style="color: #ff4500;">5</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">6</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">7</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">8</span><span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span> <span style="color: black;">&#91;</span><span style="color: #ff4500;">9</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">10</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">11</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">12</span><span style="color: black;">&#93;</span><span style="color: black;">&#125;</span>
&nbsp;
OYOOYO <span style="color: #66cc66;">=</span> <span style="color: black;">&#123;</span>
    <span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">2</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">3</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">4</span><span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span>
    <span style="color: black;">&#91;</span><span style="color: #ff4500;">5</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">6</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">7</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">8</span><span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span>
    <span style="color: black;">&#91;</span><span style="color: #ff4500;">9</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">10</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">11</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">12</span><span style="color: black;">&#93;</span>
<span style="color: black;">&#125;</span>  <span style="color: #808080; font-style: italic;"># yapf: disable</span></pre></td></tr></table></div>

<p>Yapf existe en ligne de commande, mais peut être utilisé comme une lib. En prime, avec <code>-i</code>, il peut modifier le fichier sur place au lieu de juste faire l&#8217;output dans le terminal.</p>
<p>J&#8217;espère vraiment qu&#8217;il va gagner en traction histoire de pouvoir mettre ça dans tous mes hook git et oublier une bonne fois pour toute les guéguerres de formatage, on a d&#8217;autres chattes à coder.</p>


feed_id: http://sametmax.com/?p=16045
title: Python 2 VS Python 3 : réalité de terrain 11
uri: Python-2-VS-Python-3-réalité-de-terrain-4-Recently-updated
url: http://sametmax.com/python-2-vs-python-3-realite-de-terrain/
content:
<p>A la sortie de Python 3.4, je <a href="http://sametmax.com/ca-y-est-on-peut-coder-en-python-3/">vous avais dit</a> qu&#8217;on pouvait enfin coder sereinement en Python 3. Mais en pratique, qu&#8217;est-ce que je vois dans la vie de tous les jours ?</p>
<p>Ca y est, je fais plus de Python 3 que de Python 2 ! </p>
<p>50 % de mes formations, on me demande du Python 3. On ne me demande du 2 que pour des personnes coincées avec du code legacy, ou dans des domaines à la traine comme les GIS.</p>
<p>Quand je commence un projet, je commence toujours en python 3, sauf si je dois utiliser Twisted. Tous les autres trucs qui m&#8217;intéressent <a href="http://python3wos.appspot.com/">ont été portés.</a> Et vous savez quoi ? Le portage de Twisted a <a href="https://twistedmatrix.com/trac/milestone/Python-3.x">repris de l&#8217;allure dernièrement</a>, par des gens motivés par <a href="http://wamp.ws/">crossbar.io</a> :)</p>
<p>La raison majeure qui me force à faire du Python 2 est le travail sur d&#8217;anciens projets comme des sites de culs de Max qui ont été commencé il y a des années.</p>
<p>Bien que je déteste toujours cordialement devoir taper ces putains de parenthèses pour faire un <code>print</code>, voici ce que j&#8217;adore :</p>
<ul>
<li>Le texte est 100X plus facile. Je n&#8217;ai plus à demander à mes élèves de ne pas mettre d&#8217;accents dans leurs programmes avant qu&#8217;on arrive à la partie du cours qui explique l&#8217;encoding.</li>
<li>pip est intégré (en Python 2 aussi maintenant, mais seulement sur une version toute neuve). Et le shell autocomplète même sans ipython.</li>
<li>L&#8217;unpacking avancé. C&#8217;est pratique. C&#8217;est très pratique.</li>
<li>Les nouvelles exceptions : plus claires, plus facile à comprendre et à filtrer. Love.</li>
<li>Le nouveau format de retour de la fonction <code>type()</code>. Tellement plus logique.</li>
<li>Pas besoin de se poser des questions sur l&#8217;usage de <code>item()</code>, <code>iteritems()</code>, <code>items_view()</code>, etc.</li>
<li>Plein de petits polish. Des inconsistances qu&#8217;il fallait connaître par cœur avant ont juste disparu.</li>
</ul>
<p>En fait, à la programmation, Python 3 est plus sympa, mais pas révolutionnaire. Et puis des détails comme la suppression de <code>%</code> pour le type <code>byte</code> a bien fait chier tout le monde, et heureusement a été inversé en 3.5.</p>
<p>Mais par contre à enseigner&#8230; C&#8217;est juste fantastique. Pour les nouveaux venus, le changement est incroyable. </p>


feed_id: http://sametmax.com/?p=16055
title: Lancer pdb dès qu’une exception a lieu 9
uri: Lancer-pdb-dès-qu-une-exception-a-lieu-1
url: http://sametmax.com/lancer-pdb-des-quune-exception-a-lieu/
content:
<p>Vous vous souvenez de <a href="http://sametmax.com/gestion-des-erreurs-en-python/">excepthook</a> et de <a href="http://sametmax.com/debugger-en-python-les-bases-de-pdb/">pdb</a> ?</p>
<p>Mélangeons les deux !</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">&nbsp;
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">sys</span>
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">traceback</span>
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">pdb</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> pdb_post_mortem<span style="color: black;">&#40;</span>exc_type<span style="color: #66cc66;">,</span> exc_val<span style="color: #66cc66;">,</span> exc_tb<span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;"># On affiche l'exception histoire de savoir ce qu'on debug</span>
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;&quot;</span>.<span style="color: black;">join</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">traceback</span>.<span style="color: black;">format_exception</span><span style="color: black;">&#40;</span>exc_type<span style="color: #66cc66;">,</span> exc_val<span style="color: #66cc66;">,</span> exc_tb<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
    <span style="color: #808080; font-style: italic;"># On balance pdb en mode post mortem, c'est à dire qu'il va se lancer</span>
    <span style="color: #808080; font-style: italic;"># malgré le fait que le programme ne marche plus, donnant accès</span>
    <span style="color: #808080; font-style: italic;"># au contexte qu'il y avait juste avant que ça foire</span>
    <span style="color: #dc143c;">pdb</span>.<span style="color: black;">post_mortem</span><span style="color: black;">&#40;</span>exc_tb<span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># On dit à python de lancer cette fonction quand il plante</span>
<span style="color: #dc143c;">sys</span>.<span style="color: black;">excepthook</span> <span style="color: #66cc66;">=</span> pdb_post_mortem
&nbsp;
<span style="color: #808080; font-style: italic;"># On fait planter Python histoire de voir que ça marche bien</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> boom<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    a <span style="color: #66cc66;">=</span> <span style="color: #ff4500;">1</span>
    b <span style="color: #66cc66;">=</span> a / <span style="color: #ff4500;">0</span>
boom<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Et si quand ça plante, Python nous pond la stack trace, puis nous lance un joli prompt de debugging qui donne accès à ce qu&#8217;on avait en mémoire just avant que la VM ne décède :</p>
<pre>Traceback (most recent call last):
  File "test.py", line 16, in <module>
    boom()
  File "test.py", line 14, in boom
    b = a / 0
ZeroDivisionError: integer division or modulo by zero

> /home/sam/Bureau/test.py(14)test()
-> a = 1 / 0
(Pdb) 1
(Pdb) print a
1</pre>
<p>C&#8217;est plus ou moins l&#8217;équivalent de lancer son programme manuellement avec :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="bash" style="font-family:monospace;">python <span style="color: #660033;">-m</span> pdb programme.py</pre></td></tr></table></div>

<p>L&#8217;avantage de la première forme, c&#8217;est qu&#8217;on peut le setter et l&#8217;oublier, on faire une config un peu plus custom. L&#8217;avantage de la deuxième forme, c&#8217;est que c&#8217;est juste une ligne à taper, et en prime si on fait <code>c</code>, le programme redémarre automatiquement.</p>


feed_id: http://sametmax.com/?p=16062
title: Django, une app à la fois passe à Python 3 8
uri: Django-une-app-à-la-fois-passe-à-Python-3-3
url: http://sametmax.com/django-une-app-a-la-fois-passe-a-python-3/
content:
<p>Beaucoup de nos projets ne sont pas encore compatibles Python 3 : 0bin, batbelt&#8230; La raison n&#8217;est pas technique, mais purement humaine, liée à notre monopilosité intramanuelle.</p>
<p>Néanmoins ayant posté sur reddit dernièrement le projet <a href="https://github.com/sametmax/Django--an-app-at-a-time/tree/fran%C3%A7ais">Django, une app à la fois</a>, on m&#8217;a demandé de le rafraichir.</p>
<p>Je l&#8217;ai donc up à Django 1.8, il est maintenant compatible avec Python 3 et gagne une licence MIT.</p>
<p>Et boom, just like that, un projet qui existe depuis 2 ans est passé dans <a href="https://github.com/trending">la liste des trending repositories de github</a>. </p>


feed_id: http://sametmax.com/?p=16068
title: Le don du mois : moi 12
uri: Le-don-du-mois-moi-5
url: http://sametmax.com/le-don-du-mois-moi/
content:
<p>Je n&#8217;ai pas de thune ce mois ci, étant très, très à découvert, ce qui est directement une conséquence d&#8217;être à son compte : les clients ne paient pas toujours à temps, quand ils paient, et je passe le permis moto ce qui me rajoute des frais.</p>
<p>(Je note par ailleurs que ma strat de révision des exams n&#8217;a pas changé depuis le collège. Putain que je suis un branleur, ça n&#8217;a rien à voir avec l&#8217;adolescence.)</p>
<p>Du coup, pas de don.</p>
<p>Je publie quand même l&#8217;article pour rappeler la philosophie du don : ce n&#8217;est pas une obligation, ce n&#8217;est pas un devoir, c&#8217;est quelque chose de volontaire qu&#8217;on fait selon ses capacités.</p>
<p>Ne culpabilisez pas de ne pas donner. Si vous donnez 1 euros une fois dans l&#8217;année, c&#8217;est très bien.</p>


feed_id: http://sametmax.com/?p=16074
title: Un header d’encoding plus simple pour Python 11
uri: Un-header-d-encoding-plus-simple-pour-Python-7-Recently-updated
url: http://sametmax.com/un-header-dencoding-plus-simple-pour-python/
content:
<p>Je sais pas pour vous, mais moi je me souviens jamais de :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># -*- coding: utf-8 -*-</span></pre></td></tr></table></div>

<p>Je le copie/colle à chaque fois, et sur sublime j&#8217;ai un snippet pour le taper.</p>
<p>Je viens d&#8217;apprendre, après 10 putain d&#8217;années à coder en python, que le header suivant était parfaitement valide :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># coding: utf-8</span></pre></td></tr></table></div>

<p>Bordel de merde, pourquoi c&#8217;est pas écrit dans tous les tutos ? Pourquoi on se tape encore l&#8217;ancien ? </p>
<p>Évidement avec Python 3, y a souvent plus besoin d&#8217;en-tête du tout, mais shit, ce genre détail c&#8217;est super con. Vous imaginez pas le nombre d&#8217;élèves à qui j&#8217;ai fait apprendre la première version toute pourrie alors que la seconde est si simple.</p>
<p>Grr, dirais-je.</p>


feed_id: http://sametmax.com/?p=15826
title: Minitip pew et OSX
uri: Minitip-pew-et-OSX
url: http://sametmax.com/minitip-pew-et-osx/
content:
<p style="text-align: center;"><em><small>Ceci est un post invité de <a href="http://sametmax.com/author/coyote/">coyote</a> posté sous licence <a href="http://creativecommons.org/licenses/by/3.0/">creative common 3.0 unported</a>.</small></em></p>
<p>Comme tout bon lecteur de S&amp;M, je me fais un devoir d&#8217;adopter tous les outils conseillés par nos maîtres (oui bon sauf crossbar.io – j&#8217;ai une vie…)</p>
<p>Donc, j&#8217;étais très heureux de découvrir <a title="pew" href="http://sametmax.com/mieux-que-python-virtualenvwrapper-pew/">pew</a> mais soyons honnête, ce n&#8217;est pas <em>exactement</em> un drop-in replacement de virtualenv-wrapper. Bien sûr, c&#8217;est très proche et c&#8217;est beaucoup mieux mais… deux-trois petites bricoles n’emmerdaient toujours.</p>
<h3>Le problème</h3>
<p><strong>bash</strong> sous OSX et Linux ont des configurations et conventions un poil différentes ce qui fait que par défaut, si vous n&#8217;êtes pas déjà au fait de ces différences, vous vous rendez compte que dès que vous activez un environnement avec pew, tout est cassé : votre prompt, vos raccourcis, etc.</p>
<p>Tout ça est dû au fait que (/!\ simplification inside) :</p>
<p>* Sous linux, au lancement de tout shell, le contenu du <em>bashrc</em> (<em>~/.bashrc</em>, <em>/etc/bashrc</em>) est exécuté.<br />
* Sous OSX, au lancement d&#8217;un terminal, le contenu du <em>~/.bash_login</em> est exécuté puis au lancement de subshell, c&#8217;est le ~/bashrc.</p>
<p>C&#8217;est con, mais ça veut dire qu&#8217;à chaque <code lang="bash">pew workon toto</code>, seul <em>.bashrc</em> est exécuté. Et généralement, sous OSX, il est vide ou non existant.</p>
<h3>La solution</h3>
<p>C&#8217;est très simple, mais ça prends quand même 5mn…</p>
<p>On ne peut pas simplement tout déplacer du .bash_login vers le .bashrc, sinon hors virtualenv ça ne marchera pas. Voici donc comment je fais moi, mais c&#8217;est juste parce que je suis paresseux.</p>
<p><strong><em>~/.bash_login</em>:</strong></p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #7a0874; font-weight: bold;">source</span> ~<span style="color: #000000; font-weight: bold;">/</span>.bashrc</pre></td></tr></table></div>

<p>Et c&#8217;est tout. En gros, on court-circuite le comportement OSX pour revenir vers du plus standard.</p>
<p><strong>Extrait du <em>~/.bashrc</em>:</strong></p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># modification de diverses variables que je veux PARTOUT (hors env et dans env)</span>
<span style="color: #7a0874; font-weight: bold;">export</span> <span style="color: #007800;">PATH</span>=<span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>local<span style="color: #000000; font-weight: bold;">/</span>mongodb-osx-x86_64-2.6.3<span style="color: #000000; font-weight: bold;">/</span>bin:<span style="color: #007800;">$PATH</span>
&nbsp;
<span style="color: #666666; font-style: italic;"># modifications que je veux uniquement HORS env</span>
<span style="color: #666666; font-style: italic;"># si vous avez d'autres versions de python ou pip dans votre path,</span>
<span style="color: #666666; font-style: italic;"># comme le .bashrc est lancé après l'inclusion du path de l'environ par pew</span>
<span style="color: #666666; font-style: italic;"># vous devez bricoler sinon vous aurez pas la bonne version. </span>
<span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">${VIRTUAL_ENV}</span>a&quot;</span> = <span style="color: #ff0000;">&quot;a&quot;</span> <span style="color: #7a0874; font-weight: bold;">&#93;</span>
	<span style="color: #000000; font-weight: bold;">then</span>
	<span style="color: #7a0874; font-weight: bold;">export</span> <span style="color: #007800;">PATH</span>=<span style="color: #ff0000;">&quot;/Library/Frameworks/Python.framework/Versions/3.4/bin:<span style="color: #007800;">${PATH}</span>&quot;</span>
<span style="color: #000000; font-weight: bold;">else</span>
        <span style="color: #666666; font-style: italic;"># modification voulues uniquement dans l'env ?</span>
<span style="color: #000000; font-weight: bold;">fi</span>
&nbsp;
<span style="color: #666666; font-style: italic;"># raccourcis pour les vieilles habitudes. c'est ce qui me derange</span>
<span style="color: #666666; font-style: italic;"># le plus avec pew :)</span>
<span style="color: #000000; font-weight: bold;">function</span> workon<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> <span style="color: #7a0874; font-weight: bold;">&#123;</span>
	pew-workon $<span style="color: #000000; font-weight: bold;">@</span>;
<span style="color: #7a0874; font-weight: bold;">&#125;</span>
&nbsp;
<span style="color: #666666; font-style: italic;"># completion pew sur le raccourci. vous connaissez le nom de vos envs vous ?</span>
_pew<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
<span style="color: #7a0874; font-weight: bold;">&#123;</span>
    <span style="color: #7a0874; font-weight: bold;">local</span> <span style="color: #007800;">cur</span>=<span style="color: #800000;">${COMP_WORDS[COMP_CWORD]}</span>
    <span style="color: #007800;">COMPREPLY</span>=<span style="color: #7a0874; font-weight: bold;">&#40;</span> $<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">compgen</span> <span style="color: #660033;">-W</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$(pew-ls)</span>&quot;</span> <span style="color: #660033;">--</span> <span style="color: #800000;">${cur}</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> <span style="color: #7a0874; font-weight: bold;">&#41;</span>
<span style="color: #7a0874; font-weight: bold;">&#125;</span>
<span style="color: #7a0874; font-weight: bold;">complete</span> <span style="color: #660033;">-F</span> _pew workon
&nbsp;
<span style="color: #666666; font-style: italic;"># renvoie le path d'un projet depuis le nom de l'env pour faire d'une pierre deux coups (optionnel)</span>
<span style="color: #666666; font-style: italic;"># utilise pyp</span>
<span style="color: #000000; font-weight: bold;">function</span> pwdof<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> <span style="color: #7a0874; font-weight: bold;">&#123;</span>
	<span style="color: #007800;">path</span>=<span style="color: #000000; font-weight: bold;">`</span><span style="color: #7a0874; font-weight: bold;">pwd</span><span style="color: #000000; font-weight: bold;">`</span>
	<span style="color: #007800;">env_name</span>=<span style="color: #000000; font-weight: bold;">`</span><span style="color: #7a0874; font-weight: bold;">echo</span> $<span style="color: #000000; font-weight: bold;">@|</span> pyp <span style="color: #ff0000;">&quot;p.split('/')[-1]&quot;</span><span style="color: #000000; font-weight: bold;">`</span>
	<span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">${env_name}</span>&quot;</span> = <span style="color: #ff0000;">&quot;toto&quot;</span> <span style="color: #7a0874; font-weight: bold;">&#93;</span>
		<span style="color: #000000; font-weight: bold;">then</span>
		<span style="color: #007800;">path</span>=~<span style="color: #000000; font-weight: bold;">/</span>src<span style="color: #000000; font-weight: bold;">/</span>toto-project;
	<span style="color: #000000; font-weight: bold;">fi</span>
&nbsp;
	<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #007800;">$path</span>;
<span style="color: #7a0874; font-weight: bold;">&#125;</span>
&nbsp;
<span style="color: #666666; font-style: italic;"># coloration du prompt a l’intérieur du subshell</span>
<span style="color: #666666; font-style: italic;"># j'aime avoir les branches git et le nom de l'env dans mon prompt.</span>
<span style="color: #666666; font-style: italic;"># donc pour que votre prompt marche dehors ET dedans (exemple)</span>
<span style="color: #000000; font-weight: bold;">function</span> color_prompt <span style="color: #7a0874; font-weight: bold;">&#123;</span>
    <span style="color: #7a0874; font-weight: bold;">local</span> <span style="color: #007800;">__user_and_host</span>=<span style="color: #ff0000;">&quot;\[\033[01;32m\]\u@\h&quot;</span>
    <span style="color: #7a0874; font-weight: bold;">local</span> <span style="color: #007800;">__cur_location</span>=<span style="color: #ff0000;">&quot;\[\033[01;34m\]\w&quot;</span>
    <span style="color: #7a0874; font-weight: bold;">local</span> <span style="color: #007800;">__git_branch_color</span>=<span style="color: #ff0000;">&quot;\[\033[31m\]&quot;</span>
    <span style="color: #7a0874; font-weight: bold;">local</span> <span style="color: #007800;">__git_branch</span>=<span style="color: #ff0000;">'`git branch 2&amp;gt; /dev/null | grep -e ^* | sed -E  s/^\\\\\*\ \(.+\)$/\(\\\\\1\)\ /`'</span>
    <span style="color: #7a0874; font-weight: bold;">local</span> <span style="color: #007800;">__prompt_tail</span>=<span style="color: #ff0000;">&quot;\[\033[35m\]$&quot;</span>
    <span style="color: #7a0874; font-weight: bold;">local</span> <span style="color: #007800;">__last_color</span>=<span style="color: #ff0000;">&quot;\[\033[00m\]&quot;</span>
    <span style="color: #7a0874; font-weight: bold;">export</span> <span style="color: #007800;">PS1</span>=<span style="color: #ff0000;">&quot;<span style="color: #007800;">$__user_and_host</span> <span style="color: #007800;">$__cur_location</span> <span style="color: #007800;">$__git_branch_color</span><span style="color: #007800;">$__git_branch</span><span style="color: #007800;">$__prompt_tail</span><span style="color: #007800;">$__last_color</span> &quot;</span>
    <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">${VIRTUAL_ENV}</span>a&quot;</span> <span style="color: #000000; font-weight: bold;">!</span>= <span style="color: #ff0000;">&quot;a&quot;</span> <span style="color: #7a0874; font-weight: bold;">&#93;</span>
    	<span style="color: #000000; font-weight: bold;">then</span>
		<span style="color: #7a0874; font-weight: bold;">export</span> <span style="color: #007800;">PS1</span>=<span style="color: #ff0000;">&quot;(<span style="color: #000099; font-weight: bold;">\$</span>(basename '<span style="color: #007800;">$VIRTUAL_ENV</span>'))<span style="color: #007800;">$PS1</span>&quot;</span>;
&nbsp;
		<span style="color: #666666; font-style: italic;"># facultatif: permet de faire un cd au lancement du subshell</span>
		<span style="color: #7a0874; font-weight: bold;">cd</span> <span style="color: #000000; font-weight: bold;">`</span>pwdof <span style="color: #800000;">${VIRTUAL_ENV}</span><span style="color: #000000; font-weight: bold;">`</span>
   	<span style="color: #000000; font-weight: bold;">fi</span>
<span style="color: #7a0874; font-weight: bold;">&#125;</span>
color_prompt
&nbsp;
<span style="color: #666666; font-style: italic;"># completion de la commande pew qui n'est pas installé par pip</span>
<span style="color: #666666; font-style: italic;"># mais qui reste pratique.</span>
<span style="color: #666666; font-style: italic;"># adapté depuis: https://github.com/berdario/pew/blob/master/pew/complete_scripts/complete.bash</span>
_pew<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
<span style="color: #7a0874; font-weight: bold;">&#123;</span>
	<span style="color: #7a0874; font-weight: bold;">local</span> <span style="color: #007800;">cur</span>=<span style="color: #800000;">${COMP_WORDS[COMP_CWORD]}</span>
	<span style="color: #7a0874; font-weight: bold;">local</span> <span style="color: #007800;">prev</span>=<span style="color: #800000;">${COMP_WORDS[COMP_CWORD-1]}</span>
    <span style="color: #007800;">args</span>=<span style="color: #ff0000;">&quot;--help --python -i -a -r&quot;</span>
    <span style="color: #007800;">commands</span>=<span style="color: #ff0000;">&quot;ls add mkproject rm lssitepackages cp workon new mktmpenv setproject show wipeenv sitepackages_dir inall toggleglobalsitepackages&quot;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">case</span> <span style="color: #007800;">$prev</span> <span style="color: #000000; font-weight: bold;">in</span>
        <span style="color: #c20cb9; font-weight: bold;">ls</span><span style="color: #000000; font-weight: bold;">|</span>show<span style="color: #000000; font-weight: bold;">|</span><span style="color: #c20cb9; font-weight: bold;">rm</span><span style="color: #000000; font-weight: bold;">|</span>workon<span style="color: #000000; font-weight: bold;">|</span><span style="color: #c20cb9; font-weight: bold;">cp</span><span style="color: #000000; font-weight: bold;">|</span>setproject<span style="color: #7a0874; font-weight: bold;">&#41;</span>
            <span style="color: #007800;">COMPREPLY</span>=<span style="color: #7a0874; font-weight: bold;">&#40;</span> $<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">compgen</span> <span style="color: #660033;">-W</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$(pew-ls)</span>&quot;</span> <span style="color: #660033;">--</span> <span style="color: #800000;">${cur}</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> <span style="color: #7a0874; font-weight: bold;">&#41;</span>
            <span style="color: #7a0874; font-weight: bold;">return</span> <span style="color: #000000;">0</span>
            <span style="color: #000000; font-weight: bold;">;;</span>
        inall<span style="color: #7a0874; font-weight: bold;">&#41;</span>
            _command_offset <span style="color: #000000;">2</span>
            <span style="color: #7a0874; font-weight: bold;">return</span> <span style="color: #000000;">0</span>
            <span style="color: #000000; font-weight: bold;">;;</span>
        mktmpenv<span style="color: #000000; font-weight: bold;">|</span>new<span style="color: #7a0874; font-weight: bold;">&#41;</span>
            <span style="color: #007800;">COMPREPLY</span>=<span style="color: #7a0874; font-weight: bold;">&#40;</span> $<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">compgen</span> <span style="color: #660033;">-W</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">${args}</span>&quot;</span> <span style="color: #660033;">--</span> <span style="color: #800000;">${cur}</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> <span style="color: #7a0874; font-weight: bold;">&#41;</span>
            <span style="color: #7a0874; font-weight: bold;">return</span> <span style="color: #000000;">0</span>
            <span style="color: #000000; font-weight: bold;">;;</span>
        mkproject<span style="color: #7a0874; font-weight: bold;">&#41;</span>
            <span style="color: #007800;">COMPREPLY</span>=<span style="color: #7a0874; font-weight: bold;">&#40;</span> $<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">compgen</span> <span style="color: #660033;">-W</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">${args}</span> -t --list&quot;</span> <span style="color: #660033;">--</span> <span style="color: #800000;">${cur}</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> <span style="color: #7a0874; font-weight: bold;">&#41;</span>
            <span style="color: #7a0874; font-weight: bold;">return</span> <span style="color: #000000;">0</span>
            <span style="color: #000000; font-weight: bold;">;;</span>
        add<span style="color: #7a0874; font-weight: bold;">&#41;</span>
            <span style="color: #007800;">COMPREPLY</span>=<span style="color: #7a0874; font-weight: bold;">&#40;</span> $<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">compgen</span> <span style="color: #660033;">-W</span> <span style="color: #ff0000;">&quot;--help -d&quot;</span> <span style="color: #660033;">--</span> <span style="color: #800000;">${cur}</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> <span style="color: #7a0874; font-weight: bold;">&#41;</span>
            <span style="color: #7a0874; font-weight: bold;">return</span> <span style="color: #000000;">0</span>
            <span style="color: #000000; font-weight: bold;">;;</span>
    <span style="color: #000000; font-weight: bold;">esac</span>
&nbsp;
    <span style="color: #007800;">COMPREPLY</span>=<span style="color: #7a0874; font-weight: bold;">&#40;</span> $<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">compgen</span> <span style="color: #660033;">-W</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">${commands}</span>&quot;</span> <span style="color: #660033;">--</span> <span style="color: #800000;">${cur}</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> <span style="color: #7a0874; font-weight: bold;">&#41;</span>
&nbsp;
<span style="color: #7a0874; font-weight: bold;">&#125;</span>
<span style="color: #7a0874; font-weight: bold;">complete</span> <span style="color: #660033;">-F</span> _pew pew</pre></td></tr></table></div>

<p>Et voilà !</p>
<p>Ça casse pas trois pattes à un canard mais si vous êtes sous OSX, que vous avez installé, vu que c&#8217;était pas parfait puis vous êtes dit «on verra plus tard» et bien le moment est arrivé.</p>


feed_id: http://sametmax.com/?p=16085
title: Les slices, c’est rapide et c’est beau 19
uri: Les-slices-c-est-rapide-et-c-est-beau
url: http://sametmax.com/les-slices-cest-rapide-et-cest-beau/
content:
<p>Si vous faites de l&#8217;analyse de gros jeux de données en Python, vous vous êtes vite rendu compte que c&#8217;est là que le langage montre sa lenteur.</p>
<p>Les boucles pour manipuler des arrays d&#8217;entiers, qui prennent quelque nanosecondes en C, prennent des microsecondes en Python. C&#8217;est pour ça que les scientifiques utilisent SciPy et les analystes Pandas, qui sont tous deux basés sur la lib C Numpy bien enrobée dans du joli Python.</p>
<p>Parfois néanmoins, garder le code en pur Python est un objectif, comme dans le cas du projet <a href="https://pypi.python.org/pypi/mss/">mss</a>, un screenshotter qui ne souhaites avoir une extension compilée attachée à la patte.</p>
<p>Or la manipulation d&#8217;images, ça bouffe des grosses matrices de pixels, et l&#8217;auteur nous a posé une <a href="http://indexerror.net/1338/swap-efficient?show=1356">jolie colle</a> sur IndexError : ayant un array de pixels en notation BGR (Blue, Green Red), comment le transposer en RGB de manière performante ?</p>
<p>Sa proposition était :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">pixels <span style="color: #66cc66;">=</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">300</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># je réduis le nombre de pixel pour le benchmark</span>
buffer_len <span style="color: #66cc66;">=</span> <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>pixels<span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> version1<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">for</span> idx <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span><span style="color: #66cc66;">,</span> buffer_len - <span style="color: #ff4500;">2</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">3</span><span style="color: black;">&#41;</span>:
        pixels<span style="color: black;">&#91;</span>idx + <span style="color: #ff4500;">2</span><span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span> pixels<span style="color: black;">&#91;</span>idx<span style="color: black;">&#93;</span> <span style="color: #66cc66;">=</span> pixels<span style="color: black;">&#91;</span>idx<span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span> pixels<span style="color: black;">&#91;</span>idx + <span style="color: #ff4500;">2</span><span style="color: black;">&#93;</span></pre></td></tr></table></div>

<p>J&#8217;ai tenté :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">from</span> <span style="color: #dc143c;">array</span> <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">array</span>
<span style="color: #008000;">xrange</span> <span style="color: #66cc66;">=</span> <span style="color: #008000;">getattr</span><span style="color: black;">&#40;</span>__builtins__<span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'xrange'</span><span style="color: #66cc66;">,</span> <span style="color: #008000;">range</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> version2<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">def</span> to_rgb<span style="color: black;">&#40;</span>pixels<span style="color: #66cc66;">,</span> buffer_len<span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">xrange</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span><span style="color: #66cc66;">,</span> buffer_len - <span style="color: #ff4500;">2</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">3</span><span style="color: black;">&#41;</span>:
            <span style="color: #ff7700;font-weight:bold;">yield</span> pixels<span style="color: black;">&#91;</span>i + <span style="color: #ff4500;">2</span><span style="color: black;">&#93;</span>
            <span style="color: #ff7700;font-weight:bold;">yield</span> pixels<span style="color: black;">&#91;</span>i + <span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span>
            <span style="color: #ff7700;font-weight:bold;">yield</span> pixels<span style="color: black;">&#91;</span>i<span style="color: black;">&#93;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #dc143c;">array</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'H'</span><span style="color: #66cc66;">,</span> to_rgb<span style="color: black;">&#40;</span>pixels<span style="color: #66cc66;">,</span> buffer_len<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Mais mesurer révèle que cette solution est au final bien plus lente que celle de l&#8217;auteur :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">timeit</span>
<span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">timeit</span>.<span style="color: #dc143c;">timeit</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'version1()'</span><span style="color: #66cc66;">,</span> setup<span style="color: #66cc66;">=</span><span style="color: #483d8b;">'from __main__ import version1'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #808080; font-style: italic;">#16.9543120861</span>
<span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">timeit</span>.<span style="color: #dc143c;">timeit</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'version2()'</span><span style="color: #66cc66;">,</span> setup<span style="color: #66cc66;">=</span><span style="color: #483d8b;">'from __main__ import version2'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #808080; font-style: italic;">#42.7808477879</span></pre></td></tr></table></div>

<p>C&#8217;est bubulle qui va nous pondre une solution originale, élégante, mais surtout 5 fois plus rapide, ce qui est complètement inattendu :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> version3<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    pixels<span style="color: black;">&#91;</span><span style="color: #ff4500;">2</span>:buffer_len:<span style="color: #ff4500;">3</span><span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span> pixels<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span>:buffer_len:<span style="color: #ff4500;">3</span><span style="color: black;">&#93;</span> <span style="color: #66cc66;">=</span> pixels<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span>:buffer_len:<span style="color: #ff4500;">3</span><span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span> pixels<span style="color: black;">&#91;</span><span style="color: #ff4500;">2</span>:buffer_len:<span style="color: #ff4500;">3</span><span style="color: black;">&#93;</span></pre></td></tr></table></div>

<p>Il utilise 3 astuces en une :</p>
<ul>
<li>Le swap de variable par unpacking: a, b = b, a. On sait que c&#8217;est plus rapide que deux assignation car Python saute la version intermédiaire.</li>
<li>Le slicing avec pas (l[debut:fin:pas]), et il parcours donc son array de 3 en 3. Super malin ! Non seulement je n&#8217;y aurais jamais pensé, mais en prime j&#8217;aurais imaginé que créer deux nouveaux arrays à partir du premier serait lent.</li>
<li>L&#8217;assignation de slices. Oui, on peut faire l[3:5] = [&#8216;a&#8217;, &#8216;b&#8217;] en Python.</li>
</ul>
<p>Le gain de perf est assez bluffant :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">timeit</span>.<span style="color: #dc143c;">timeit</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'version3()'</span><span style="color: #66cc66;">,</span> setup<span style="color: #66cc66;">=</span><span style="color: #483d8b;">'from __main__ import version3'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #808080; font-style: italic;">#1.84227705002</span></pre></td></tr></table></div>

<p>Pourquoi est-ce aussi rapide ? Je ne peux que faire des suppositions.</p>
<p>Je pense que faisant cette opération sans boucler explicitement, une bonne partie reste dans l&#8217;implémentation en C sous-jacente. On évite notamment pas mal d&#8217;appels à <code>__getitem__</code> et <code>__setitem__</code> qui sont toujours coûteux en Python.</p>
<p>Par curiosité, j&#8217;ai lancé le même test sur pypy :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff4500;">0.359977960587</span>
<span style="color: #ff4500;">15.5387830734</span>
<span style="color: #ff4500;">0.750488996506</span></pre></td></tr></table></div>

<p>On voit l&#8217;effet de la compilation JIT puisque la boucle explicite redevient plus performante.</p>
<p>Mais du coup je me pose une question : pourquoi ma version, qui utilise une boucle explicite également, reste autant à la traine ?</p>
<p>Puis j&#8217;ai réalisé : l&#8217;array stock des entier C, mais quand on les sort, il faut les rewrapper dans des entiers Python. Donc ma boucle se tape cette conversion à chaque tour, et ça bouffe.</p>
<p>Je vire l&#8217;array :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> version4<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">def</span> to_rgb<span style="color: black;">&#40;</span>pixels<span style="color: #66cc66;">,</span> buffer_len<span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">xrange</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span><span style="color: #66cc66;">,</span> buffer_len - <span style="color: #ff4500;">2</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">3</span><span style="color: black;">&#41;</span>:
            <span style="color: #ff7700;font-weight:bold;">yield</span> pixels<span style="color: black;">&#91;</span>i + <span style="color: #ff4500;">2</span><span style="color: black;">&#93;</span>
            <span style="color: #ff7700;font-weight:bold;">yield</span> pixels<span style="color: black;">&#91;</span>i + <span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span>
            <span style="color: #ff7700;font-weight:bold;">yield</span> pixels<span style="color: black;">&#91;</span>i<span style="color: black;">&#93;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">list</span><span style="color: black;">&#40;</span>to_rgb<span style="color: black;">&#40;</span>pixels<span style="color: #66cc66;">,</span> buffer_len<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Et pouf, le temps devient plus raisonnable.</p>
<p>Avec CPython : 1.84687900543<br />
Avec Pypy : 0.274104118347</p>
<p>Sur CPython, la vitesse est du même ordre de grandeur que la version avec les slices.</p>
<p>Sur PyPy, la version est 2X plus rapide que les slices, est 25% plus rapide que la version originale.</p>
<p>Moralités :</p>
<ul>
<li>Les slices, c&#8217;est rapide. Et beau.</li>
<li>Bien connaitre ses structures de données. Utiliser la mauvaise vous tue les perfs, et <code>array</code> sert à économiser de la place en mémoire, pas à gagner du CPU.</li>
<li>Pypy, ça trace, mais le gain de perf peut se déplacer d&#8217;un algo à l&#8217;autre.</li>
</ul>


feed_id: http://sametmax.com/?p=16108
title: Python-like n’a aucun intérêt 17
uri: Python-like-n-a-aucun-intérêt-7
url: http://sametmax.com/python-like-na-aucun-interet/
content:
<p>On voit passer des technos ici et là qui annoncent &#8220;un langage qui a un goût de Python&#8221;, &#8220;une syntaxe Python like&#8221;, &#8220;un preprocesseur qui converti un code compatible Python en JS&#8221;, etc.</p>
<p>Ça n&#8217;a aucun intérêt.</p>
<p>Oui, la syntaxe de Python fait parti de ses points forts, d&#8217;une des raisons qu&#8217;on aime le langage. Mais la syntaxe n&#8217;est PAS le langage.</p>
<p>Python, c&#8217;est un standard qui signifie que mon code Python tourne sur CPython, Pypy, IronPython et Jython. Ce n&#8217;est pas qu&#8217;une syntaxe. C&#8217;est aussi l&#8217;accès à une gigantesque <a href="http://sametmax.com/quest-ce-que-la-bibliotheque-standard-python/">stdlib</a>, à des milliers de paquet sur pypi, à de la métaprogrammation, à la capacité de créer des threads, du multiprocessing, des coroutines, d&#8217;accéder au système de fichier, d&#8217;attaquer une base de données, de traiter les dates, etc.</p>
<p>Ce n&#8217;est pas juste la possibilité de faire :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: black;">&#91;</span>x * <span style="color: #ff4500;">2</span> <span style="color: #ff7700;font-weight:bold;">for</span> x <span style="color: #ff7700;font-weight:bold;">in</span> iterable <span style="color: #ff7700;font-weight:bold;">if</span> condition<span style="color: black;">&#93;</span></pre></td></tr></table></div>

<p>Au passage, généralement les Python-like, ne font même pas ça correctement. Oubliant qu&#8217;en python on peut faire aussi :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: black;">&#91;</span>x * <span style="color: #ff4500;">2</span> <span style="color: #ff7700;font-weight:bold;">for</span> x <span style="color: #ff7700;font-weight:bold;">in</span> iterable<span style="color: black;">&#93;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">2</span>:<span style="color: #ff4500;">6</span>:<span style="color: #ff4500;">3</span><span style="color: black;">&#93;</span>
<span style="color: black;">&#40;</span>x * <span style="color: #ff4500;">2</span> <span style="color: #ff7700;font-weight:bold;">for</span> x <span style="color: #ff7700;font-weight:bold;">in</span> iterable<span style="color: black;">&#41;</span>
next<span style="color: black;">&#40;</span>x * <span style="color: #ff4500;">2</span> <span style="color: #ff7700;font-weight:bold;">for</span> x <span style="color: #ff7700;font-weight:bold;">in</span> iterable<span style="color: black;">&#41;</span>
next<span style="color: black;">&#40;</span><span style="color: black;">&#40;</span>x * <span style="color: #ff4500;">2</span> <span style="color: #ff7700;font-weight:bold;">for</span> x <span style="color: #ff7700;font-weight:bold;">in</span> iterable<span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>
<span style="color: black;">&#123;</span>x * <span style="color: #ff4500;">2</span> <span style="color: #ff7700;font-weight:bold;">for</span> x <span style="color: #ff7700;font-weight:bold;">in</span> iterable<span style="color: black;">&#125;</span>
<span style="color: black;">&#123;</span>x: x * <span style="color: #ff4500;">2</span> <span style="color: #ff7700;font-weight:bold;">for</span> x <span style="color: #ff7700;font-weight:bold;">in</span> iterable<span style="color: black;">&#125;</span>
<span style="color: black;">&#91;</span>x + y <span style="color: #ff7700;font-weight:bold;">for</span> x<span style="color: #66cc66;">,</span> y <span style="color: #ff7700;font-weight:bold;">in</span> iterable<span style="color: black;">&#93;</span>
<span style="color: black;">&#91;</span>y * <span style="color: #ff4500;">2</span> <span style="color: #ff7700;font-weight:bold;">for</span> x <span style="color: #ff7700;font-weight:bold;">in</span> iterable <span style="color: #ff7700;font-weight:bold;">for</span> y <span style="color: #ff7700;font-weight:bold;">in</span> x<span style="color: black;">&#93;</span></pre></td></tr></table></div>

<p>Bref, un truc qui fait vaguement comme Python n&#8217;est pas intéressant. Si je veux quelque chose de différent, je vais utiliser un autre langage. Si je veux Python, je vais utiliser Python. Pas un ersatz qui ne me donnera pas un dixième du potentiel d&#8217;un outil que je maîtrise très bien.</p>


feed_id: http://sametmax.com/?p=16116
title: async / await, la feature de dernière minute de Python 3.5 9
uri: async-await-la-feature-de-dernière-minute-de-Python-3-5-3-Recen
url: http://sametmax.com/async-await-la-feature-de-derniere-minute-de-python-3-5/
content:
<p>Ces mots clés vont-ils être introduits pour Python 3.5 alors qu&#8217;elle est déjà en alpha 4, et que la feature freeze est pour la prochaine version ? La release finale est prévue pour le 22 mai, ce qui est à peine un mois, pour une nouveauté <a href="https://www.python.org/dev/peps/pep-0492/#new-coroutine-declaration-syntax">formalisée début avril</a> et toujours en draft.</p>
<p>J&#8217;avoue qu&#8217;à première vue, l&#8217;idée ne m&#8217;a pas enthousiasmé.</p>
<p>D&#8217;abord, parce que ça n&#8217;apporte pas grand chose de nouveau. Les coroutines, ça existe depuis un bail maintenant, et asyncio les exploite avec <code>yield from</code>.</p>
<p>Pour résumer, la proposition est d&#8217;introduire deux mots clés tels que :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> asyncio
&nbsp;
<span style="color: #66cc66;">@</span>asyncio.<span style="color: black;">coroutine</span>
<span style="color: #ff7700;font-weight:bold;">def</span> truc<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    bidule<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">yield</span> <span style="color: #ff7700;font-weight:bold;">from</span> machine_asynchrone<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    chose<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Puisse être écrit :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">async <span style="color: #ff7700;font-weight:bold;">def</span> truc<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    bidule<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    await machine_asynchrone<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    chose<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>(Notez que la coloration syntaxique ne les prends pas en compte :))</p>
<p>Le PEP propose également l&#8217;introduction de deux syntaxes pour avoir des context managers et des boucles asynchrones: <code>async with</code> et <code>async for</code></p>
<p>Et ça ne m&#8217;a pas chauffé parce que :</p>
<ul>
<li>Je ne voyais pas l’intérêt d&#8217;ajouter des mots clés pour faire un truc qu&#8217;on peut déjà faire. Le faible nombre de key words dans Python est pour moi une feature.</li>
<li>Il n&#8217;y a rien que ça permette qu&#8217;on ne pouvait pas faire avant.</li>
<li>Ça me parait un peu fait à la dernière minute, introduit comme un voleur avant la release.</li>
<li>C&#8217;est franchement moche le <code>async</code> avec un autre mot clé et ça pête toutes les attentes qu&#8217;on a eu sur la syntaxe du langage jusqu&#8217;ici : maintenant on a des qualificateurs, ce qu&#8217;on avait jamais eu avant. Ca ajouté aux type hintings, qui sont déjà très laids, c&#8217;est charger la mule.</li>
</ul>
<p>Entre temps j&#8217;y ai réfléchi et avec le recul, je commence à voir de sérieuses qualités à cette proposition :</p>
<ul>
<li>On distingue clairement le code qui est pour créer des générateurs, et le code asynchrone. Ce sont des choses qui n&#8217;ont sémantiquement rien à voir, et utiliser <code>yield from</code> pour les deux rendait tout ça bien confus.</li>
<li>C&#8217;est moins à taper : pas besoin d&#8217;importer un décorateur de 3 km et l&#8217;apposer, et quand on a pas mal de point d&#8217;arrêt, <code>await</code> c&#8217;est moins chiant à tapper que <code>yield from</code> et plus joli.</li>
<li>Ca évite pas mal de bug subtiles qui se glissent quand on utilise une coroutine pour la première fois sans comprendre tout le système. Par exemple si on vire tous les <code>yield from</code> d&#8217;une coroutine, c&#8217;est la merde, ce qui n&#8217;est pas le cas pour les <code>await</code>.</li>
<li>Quand on fait une boucle sur un generateur on sait tout de suite si on va avoir un point d&#8217;arrêt ou non.</li>
<li>Les mêmes mots clés sont utilisés dans d&#8217;autre langage, ce qui permet aux migrants de comprendre le principe bien plus vite qu&#8217;avec <code>yield</code> qu&#8217;il faut assimiler, et apprendre à distinguer dans ses deux formes.</li>
</ul>
<p>Bref, <code>async</code> et <code>await</code> sont plus explicites, amènent moins de confusion, évitent des bugs et d&#8217;une manière générale permettent une compréhension plus rapide du code, mais également du concept de l&#8217;asynchrone en général, particulièrement pour les débutants.</p>
<p>Car j&#8217;avais en effet vu pas mal de gens ne rien piger aux coroutines.</p>
<p>Du coup, même si j&#8217;aimerais que le truc ne soit pas baclé et inséré à la va vite avant la bêta, je trouve finalement que c&#8217;est pas mal. La syntaxe n&#8217;est pas fantastique, mais je n&#8217;arrive pas à imaginer mieux (alors que clairement, les <a href="https://www.python.org/dev/peps/pep-0484/">types hinting</a> seraient 100x mieux dans la docstring avec le format existant pour sphynx), donc inutile de critiquer si on apporte pas de solution. </p>


feed_id: http://sametmax.com/?p=16128
title: Point rapide sur les types hints 6
uri: Point-rapide-sur-les-types-hints-4-Recently-updated
url: http://sametmax.com/point-rapide-sur-les-types-hints/
content:
<p>Avec la 3.5 arrive les <a href="https://www.youtube.com/watch?v=2wDvzy6Hgxg">types hints</a>.</p>
<p>Pour remettre ça dans le contexte, Python 3 avait introduit les functions annotations, c&#8217;est à dire la possibilité de rajouter une information aux paramètres et valeur de retour d&#8217;une fonction. Cette information pouvait être n&#8217;importe quel objet Python :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> add<span style="color: black;">&#40;</span>a: <span style="color: #483d8b;">&quot;n'importe quel objet&quot;</span><span style="color: #66cc66;">,</span> b: <span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span> -<span style="color: #66cc66;">&gt;</span> <span style="color: #008000;">ImportError</span>:
    <span style="color: #ff7700;font-weight:bold;">return</span> a + b</pre></td></tr></table></div>

<p>Ces annotations ne faisaient absolument rien à part être accessibles :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> add<span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span>
<span style="color: #ff4500;">3</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> add.__annotations__
<span style="color: black;">&#123;</span><span style="color: #483d8b;">'b'</span>: <span style="color: #ff4500;">1</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'a'</span>: <span style="color: #483d8b;">&quot;n'importe quel objet&quot;</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'return'</span>: <span style="color: #66cc66;">&lt;</span><span style="color: #ff7700;font-weight:bold;">class</span> <span style="color: #483d8b;">'ImportError'</span><span style="color: #66cc66;">&gt;</span><span style="color: black;">&#125;</span></pre></td></tr></table></div>

<p>Le but étant de permettre à la communauté de faire des propositions sur leur utilisation jusqu&#8217;à ce que la préférée soit retenue.</p>
<p>Aucune proposition n&#8217;a néanmoins autant de succès que de permettre optionnellement de déclarer le typage, et c&#8217;est donc ce processus qui est amorcé avec la prochaine version où l&#8217;on pourra faire :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> add<span style="color: black;">&#40;</span>a: <span style="color: #008000;">int</span><span style="color: #66cc66;">,</span> b: <span style="color: #008000;">int</span><span style="color: black;">&#41;</span> -<span style="color: #66cc66;">&gt;</span> <span style="color: #008000;">int</span>:
    <span style="color: #ff7700;font-weight:bold;">return</span> a + b</pre></td></tr></table></div>

<p>Pour les cas plus complexes, un module contient des interfaces courantes. Par exemple, si votre fonction fait la somme d&#8217;un itérable :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">from</span> typing <span style="color: #ff7700;font-weight:bold;">import</span> Iterable
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> total<span style="color: black;">&#40;</span>l: Iterable<span style="color: black;">&#41;</span>:</pre></td></tr></table></div>

<p>Si vous voulez limiter l&#8217;itérable à un itérable d&#8217;entiers :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> total<span style="color: black;">&#40;</span>l: Iterable<span style="color: black;">&#91;</span><span style="color: #008000;">int</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>:</pre></td></tr></table></div>

<p>Pour les fonctions très complexes, ça peut vite devenir très, très moche :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> truc<span style="color: black;">&#40;</span>l: Iterable<span style="color: black;">&#91;</span>Tuple<span style="color: black;">&#40;</span>Any<span style="color: black;">&#40;</span>Bidule<span style="color: #66cc66;">,</span> Machin<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span> oui<span style="color: #66cc66;">=</span><span style="color: #008000;">True</span>: <span style="color: #008000;">bool</span><span style="color: #66cc66;">,</span> **kwargs<span style="color: black;">&#41;</span> -<span style="color: #66cc66;">&gt;</span> FuckIt:
    <span style="color: #ff7700;font-weight:bold;">return</span> FuckIt<span style="color: black;">&#40;</span>l<span style="color: #66cc66;">,</span> oui<span style="color: #66cc66;">,</span> **kwargs<span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Par ailleurs, le module <code>typing</code> va devenir une des rares bonnes raisons d&#8217;utiliser <code>import *</code> :)</p>
<p>La spec prévoit qu&#8217;on puisse mettre ces annotations dans un fichier séparé du code avec juste la signature des fonctions. D&#8217;un côté, ça a le bénéfice de permettre d&#8217;annoter un code inaltérable, ou en Python 2.7. D&#8217;un autre, le DRY va du coup aller se faire foutre et franchement, je code pas en Python pour avoir des headers comme en C.</p>
<p>L&#8217;implémentation originale ne fera strictement rien. Elle est juste là pour voir ce que les outils vont en faire : un IDE pourra facilement trouver une erreur de type, on pourra faire des hooks git qui vérifient qu&#8217;on n&#8217;a pas niqué notre code en balançant un mauvais type et pypy/cython/nuikta/numba vont pouvoir se rouler dans la boue des optimisations.</p>
<p>Cela veut dire que si j&#8217;ignore mon IDE et que je passe des arguments d&#8217;un type qui n&#8217;est pas annoté, Python l&#8217;exécutera quand même. Ouf.</p>
<p>Le bilan ?</p>
<p>Globalement positif.</p>
<p>C&#8217;est vrai que c&#8217;est méga moche. Et les <a href="http://aroberge.blogspot.fr/2015/01/type-hinting-in-python-focus-on.html?m=1">propositions</a> <a href="https://github.com/dobarkod/typedecorator">alternatives</a> ne sont pas mieux.</p>
<p>Je rêve que les annotations dans les docstrings soient utilisées, mais Guido a dit <a href="https://twitter.com/gvanrossum/status/560944233519915008">niet</a> pour des raisons que je trouve faiblement fondées : les dosctrings sont un format libre dur à parser et alors que la syntaxe Python est structurée, avec un bon lexer. L&#8217;argument avancé dans le PEP est <a href="https://www.python.org/dev/peps/pep-0484/#other-backwards-compatible-conventions">carrément faible</a> : les docstrings ça se fold dans tous les éditeurs, c&#8217;est tout l&#8217;avantage.</p>
<p>Perso, je pense que normaliser enfin le format des docstrings ne me parait pas une mauvaise chose. Et puis si on arrive à parser le HTML pourri qu&#8217;on trouve sur le Web, 3 lignes de docstrings, c&#8217;est pas la mer à boire.</p>
<p>Néanmoins c&#8217;est optionnel, souple, et la première implémentation ne se mouille pas trop, ce qui laisse de la marge pour corriger les problèmes qui vont forcément venir.</p>
<p>Le bénéfice potentiel est énorme.</p>
<p>D&#8217;un côté, on aura toujours un langage facile à apprendre et enseigner, le duck typing, l&#8217;exploration de code, le typage dynamique par défaut.</p>
<p>De l&#8217;autre, quand un surcroit de rigueur sera nécessaire, on pourra rajouter un filet de sécurité. Et dans quelques temps, peut-être même gagner sérieusement en perf.</p>
<p>Mais quand même, putain c&#8217;est moche.</p>


feed_id: http://sametmax.com/?p=16141
title: Le débat sur la programmation fonctionnelle en Python 75
uri: Le-débat-sur-la-programmation-fonctionnelle-en-Python-1
url: http://sametmax.com/le-debat-sur-la-programmation-fonctionnelle-en-python/
content:
<p>L&#8217;écosystème Python est en ébullition depuis la 3.4 et asyncio, tout le monde se sent pousser des ailes de faire évoluer la stack. La 3.5 vient réintroduire le fameux opérateur <code>%</code> pour les bytes, sa disparition ayant fait bien chier tous les développeurs réseaux, on rajoute l&#8217;opérateur <code>@</code> (qui ne fait rien, mais qui servira à numpy pour les opérations sur les matrices), il y a bien entendu le <a href="http://sametmax.com/async-await-la-feature-de-derniere-minute-de-python-3-5/">débat</a> sur <code>async</code>/<code>await</code> et enfin le gros morceau : le <a href="sametmax.com/point-rapide-sur-les-types-hints/">type hinting</a>.</p>
<p>C&#8217;est une période formidable pour la communauté car il rappelle que Python, un langage plus vieux que Java, un langage qui est maintenant considéré comme main stream &#8211; utilisé par des sociétés corporate et l’éducation nationale &#8211; ne restera pas sur ses acquis et va continuer à se réinventer.</p>
<p>Pour cette même raison, il existe un débat parallèle qui a lieu plutôt sur reddit, hackernews, la mailling list de Python-dev et Python-idea ou par PR github interposées sur des projets type <a href="https://github.com/tobgu/pyrsistent">pyrsistent</a>. Il s&#8217;agit de faire de Python un langage fonctionnel.</p>
<h2>La programmation fonctionnelle, c&#8217;est quoi ?</h2>
<p>Ce n&#8217;est pas juste utiliser des fonctions.</p>
<p>Il y a plusieurs caractéristiques à la prog fonctionnelle, mais la plus importante est que tout est immutable (les données ne peuvent être modifiées), et par corollaire, que rien n&#8217;a d&#8217;effet de bord.</p>
<p>Ce qui signifie que dans un langage purement fonctionnel, une structure comme la liste n&#8217;aurait pas de méthode qui ne retourne rien comme <code>append()</code> ou <code>pop()</code>.</p>
<p><code>liste.append(element)</code> serait remplacé par <code>liste + [element]</code>.</p>
<p><code>element = liste.pop()</code> serait remplacé par <code>liste, element = liste[:-1], liste[-1]</code></p>
<p>Vous notez qu&#8217;on ne modifie pas la liste initiale, on recrée de nouvelles structures de données à chaque fois.</p>
<p>Une alternative serait que ces méthodes retournent une nouvelle liste plutôt que <code>None</code>.</p>
<p>Bref, c&#8217;est comme si on avait que des tuples :)</p>
<p>Bien qu&#8217;on puisse créer des formes de programmations orientées objet qui n&#8217;impliquent pas de mutabilité, dans les faits les implémentations sont pour la plupart basées justement sur le fait qu&#8217;on puisse modifier les objets, aussi on oppose souvent FP et OOP.</p>
<p>Une autre caractéristique est qu&#8217;on doit pouvoir remplacer toute expression par son résultat suivant sans changer le sens du programme. C&#8217;est très élégant :</p>
<p><code>[1, 2, 3] + [4]</code> peut être réécrit <code>[1, 2, 3, 4]</code>, et le programme aura toujours le même sens. Il n&#8217;y a pas de notion de référence dont il faut se soucier, seulement les valeurs. Cela élimine naturellement un paquet de bugs et il n&#8217;y a pas de bonne pratique à appliquer ou apprendre sur la modification des données puisque le langage vous force à coder proprement.</p>
<p>En programmation fonctionnelle, la récursion est donc souvent mise en avant. Par exemple, supposons qu&#8217;on calcule la taille d&#8217;une liste ainsi en programmation traditionnelle :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> size<span style="color: black;">&#40;</span>l<span style="color: black;">&#41;</span>:
    s <span style="color: #66cc66;">=</span> <span style="color: #ff4500;">0</span>
    <span style="color: #ff7700;font-weight:bold;">for</span> x <span style="color: #ff7700;font-weight:bold;">in</span> l:
        s +<span style="color: #66cc66;">=</span> <span style="color: #ff4500;">1</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> s</pre></td></tr></table></div>

<p>Voici une forme possible en programmation fonctionnelle :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> size<span style="color: black;">&#40;</span>l<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> l:
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #ff4500;">0</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #ff4500;">1</span> + size<span style="color: black;">&#40;</span>l<span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span>:<span style="color: black;">&#93;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>La raison pour cela est qu&#8217;on peut substituer chaque expression à son résultat. Avec <code>l = [1, 2, 3]</code>:</p>
<p><code>size(l)</code> devient <code>size([1, 2, 3])</code>, qui devient <code>1 + size([2, 3])</code> qui devient <code>1 + 1 + size([3])</code> qui devient <code>1 + 1 + 1 + size([])</code> qui devient <code>1 + 1 + 1 + 0</code> qui devient <code>4</code>.</p>
<p>Quelle que soit la forme remplacée, le fonctionnement du programme est rigoureusement identique.</p>
<p>Il devient alors plus facile de prouver qu&#8217;un programme marche, de le tester, et surtout, de travailler de manière concurrente : si rien ne se modifie, nul besoin de lock et de synchronisation car rien n&#8217;est partagé et toute instruction a toujours le même comportement quel que soit le contexte.</p>
<h2>Python possède déjà des features fonctionnelles</h2>
<p>Comme en Python on peut programmer en utilisant plusieurs paradigmes, il n&#8217;y a rien d&#8217;étonnant à ce qu&#8217;on retrouve des amateurs de plusieurs écoles dans les core devs et les outils qui vont avec.</p>
<p>Bien que les listes, les sets, les objets et les dictionnaires soient mutables, les tuples, les chaînes et les entiers ne le sont pas. Par ailleurs, les fonctions sont &#8220;des citoyens de première classe&#8221;, ce qui est considéré comme un pré-requis pour la programmation fonctionnelle. Cette expression signifie qu&#8217;on peut manipuler les fonctions elles-mêmes, les créer dynamiquement, les retourner et les passer en paramètre (c.f: les <a href="sametmax.com/comprendre-les-decorateurs-python-pas-a-pas-partie-1/">décorateurs</a>).</p>
<p>Même si ce n&#8217;est pas explicitement nécessaire pour faire de la programmation fonctionnelle, tout langage fonctionnel sérieux vient avec 5 outils de base :</p>
<ul>
<li><code>map()</code>: appliquer une fonction qui transforme chaque élément d&#8217;un iterable pour en obtenir un nouveau.</li>
<li><code>filter()</code>: appliquer une fonction pour filtrer chaque élément d&#8217;un iterable et en obtenir un nouveau.</li>
<li><code>reduce()</code>: appliquer une fonction aux deux premiers élements d&#8217;un iterable, puis au résultat de cette fonction et à l&#8217;élément suivant, et ainsi de suite, jusqu&#8217;à obtenir un résultat.</li>
<li>Les <a href="http://sametmax.com/fonctions-anonymes-en-python-ou-lambda/">fonctions anonymes</a>: des fonctions qui peuvent se définir sans bloc ni nom.</li>
<li>La récursion: une fonction peut s&#8217;appeler elle-même.</li>
</ul>
<p>Python possède ces outils : <code>map()</code> et <code>filter()</code> sont des builtins, <code>reduce()</code> peut être trouvé dans le module <code>functools</code> et les fonctions anonymes peuvent être créés avec le mot clés <code>lambda</code>. Et bien sûr, une fonction peut s&#8217;appeler elle-même.</p>
<p>Voyons comment créer une liste de carrés de tous les nombres impairs de 0 à 9 :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">carres <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>
<span style="color: #ff7700;font-weight:bold;">for</span> x <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">10</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">if</span> x % <span style="color: #ff4500;">2</span>:
        carres.<span style="color: black;">append</span><span style="color: black;">&#40;</span>x * x<span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>La version fonctionnelle avec <code>map()</code>/<code>filter()</code> et des fonctions anonymes :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #008000;">list</span><span style="color: black;">&#40;</span><span style="color: #008000;">map</span><span style="color: black;">&#40;</span><span style="color: #ff7700;font-weight:bold;">lambda</span> x: x * x<span style="color: #66cc66;">,</span>  <span style="color: #008000;">filter</span><span style="color: black;">&#40;</span><span style="color: #ff7700;font-weight:bold;">lambda</span> x: x % <span style="color: #ff4500;">2</span><span style="color: #66cc66;">,</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">10</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Néanmoins Python va plus loin, puisqu&#8217;il propose les <a href="http://sametmax.com/python-love-les-listes-en-intention-partie/">listes/sets/dictionnaires en intension</a>, qui ne sont ni plus, ni moins que que <code>map()</code>/<code>filter()</code> intégrés sous forme de syntaxe :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: black;">&#91;</span>x * x <span style="color: #ff7700;font-weight:bold;">for</span> x <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">10</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">if</span> x % <span style="color: #ff4500;">2</span><span style="color: black;">&#93;</span></pre></td></tr></table></div>

<p>Ce qui est non seulement plus concis mais plus clair et plus performant que les deux versions précédentes.</p>
<p>Donc, malgré des limites que nous verrons ensuite, Python est plutôt bien armé pour la programmation fonctionnelle. La présence des générateurs et tous les outils associés (<code>itertools</code>, <code>functools</code>, <code>yield</code>, <code>yield from</code>) viennent renforcer cet aspect orienté transformation plutôt que modification.</p>
<p>Il est par ailleurs déjà considéré comme une bonne pratique d&#8217;éviter les effets de bord le plus possible, d&#8217;utiliser des générateurs et des intensions. Bref, Python n&#8217;est pas le benêt de la programmation fonctionnelle.</p>
<h2>Les limites de Python et de la programmation fonctionnelle</h2>
<p>Malgré cela, il existe de sérieuses limites pour faire de Python un langage purement fonctionnel.</p>
<p>D&#8217;abord, les listes, les dicos et les sets sont mutables. Ensuite, la récursion est limitée par la taille de la stack (par défaut 1000 récursions), il n&#8217;y a <a href="http://sametmax.com/state-machine-en-python-en-labsence-dalgos-recursifs-beneficiant-de-tail-call-optimisation/">aucune tail call optimisation</a>. Enfin, les lambdas sont bridées à une expression.</p>
<p>Ceci n&#8217;est pas arrivé par accident, mais est le résultat d&#8217;un design du langage imposé par Guido Van Rossum, son créateur et BDFL.</p>
<p>D&#8217;abord, il faut bien se souvenir que raisonner pour modifier une structure de données, c&#8217;est beaucoup plus facile pour la machine ET l&#8217;humain que d&#8217;en recréer une.</p>
<p>Les algos de tris in place sont toujours plus rapides, les transformations in place prennent moins de mémoire, et l&#8217;accumulation est bien plus facile à concevoir, relire et debugger que la récursion.</p>
<p>J&#8217;ai déjà entendu des gens me soutenir que la FP était simple. Ces gens n&#8217;ont soit jamais essayé de former d&#8217;autres personnes à la programmation, soit sont des formateurs de merde. Je pense qu&#8217;au moins ce blog me donne un minimum de crédibilité sur mes qualités de pédagogue et je m&#8217;érige donc en tant que prophète de l&#8217;intelligibilité :</p>
<blockquote><p>
En vérité, je vous le dis, la programmation fonctionnelle, c&#8217;est dur à faire comprendre.
</p></blockquote>
<p>Erlang, Lisp et Haskel ne sont pas user friendly.</p>
<p>Ne me faites pas dire ce que je n&#8217;ai pas dis. Ce sont de beaux langages, des outils performants et utiles, mais Python est 100 fois plus facile à utiliser. Il n&#8217;y a aucune comparaison possible, ce n&#8217;est même pas sur la même échelle sur le graphe.</p>
<p>Ensuite, le monde n&#8217;est pas immutable : les choses ont des états à un instant t. En informatique, une connexion réseaux a un état, un système de fichier a un état, une session a un état, etc. Les langages fonctionnels ont donc recours à tout un tas d&#8217;astuces et d&#8217;enrobages pour les manipuler comme si ce n&#8217;était pas les cas. La fameuse &#8220;simplicité&#8221;, &#8220;élégance&#8221; et &#8220;pureté&#8221; qu&#8217;ils prônent en prend un coup.</p>
<p>Les meilleurs design patterns fonctionnels peuvent devenir un enfer pour travailler avec, les monades étant l&#8217;exemple le plus couramment cité. Déjà que c&#8217;est pas évident de faire passer la OOP, les générateurs, les classes et les décorateurs&#8230; Bonne chance pour les monades, et merci pour le poisson !</p>
<p>La limite de récursion et de la taille des lambdas est également parfaitement volontaire. Comprenez bien : tous les développeurs n&#8217;ont pas (et n&#8217;ont pas à avoir) le même niveau. Mettre un géographe devant une récursion avec injection de dépendance est aussi productif que de demander à un programmeur Web de calculer lui-même sa projection mercator.</p>
<p>Si demain la récursion devient plus facile, les dev chevronnés vont massivement l&#8217;utiliser même quand ce n&#8217;est pas indispensables : donnez un jouet à un geek, et il va s&#8217;en servir. Mais <strong>la lisibilité est primordiale, c&#8217;est une feature de Python</strong>. Les codes deviendront alors soudainement significativement plus durs à lire et à débugger, pour un gain minime. En effet, la récursion ne m&#8217;a JAMAIS manqué en Python. Les développeurs ne sont pas raisonnables, ils ne vont jamais se dire, je vais m&#8217;assurer que ce code sera facile à lire pour un débutant ou moi sans café, ils vont utiliser tous les outils à leur disposition. Guido a donc volontairement limité les outils à ce qui garde un code facile à appréhender.</p>
<p>C&#8217;est ce qui a fait le succès de Python jusqu&#8217;à présent. C&#8217;est un langage facile à prendre en main, et productif. Lire le code d&#8217;un autre est simple.</p>
<p>Lire le code Lisp d&#8217;un autre n&#8217;est PAS simple.</p>
<p>Une stack trace d&#8217;une erreur en pleine récursion est pleinement inutile.</p>
<p>Le callback hell de Javascript plein de fonctions anonymes en cascade est dégueulasse.</p>
<p>Vous allez me répondre : &#8220;les gens n&#8217;ont qu&#8217;a programmer proprement&#8221; où &#8220;il y a des outils pour ça&#8221;</p>
<p>Outre le fait que pouvoir coder en Python avec juste notepad et la console est une des ses meilleures features, c&#8217;est ignorer la nature humaine.</p>
<p>On pourrait penser que quelque chose d&#8217;aussi simple qu&#8217;une indentation propre et un espacement consistant est la base.</p>
<p>Mais non.</p>
<p>Jetez un œil à n&#8217;importe quel programme JS ou PHP de petite ou moyenne taille, et vous trouverez invariablement des blocs de traviole, des variables globales, des espaces qui dégueulent à droite et à gauche et des saloperies en tout genre.</p>
<p>Python force l&#8217;indentation. Python a un PEP8.</p>
<p>J&#8217;adore ça.</p>
<p>Ca amène les porcs à coder plus proprement.</p>
<p>C&#8217;est pareil pour les lambdas et la récursion. On force la main aux gens déraisonnables pour qu&#8217;ils ne fassent pas de connerie. Désolé, je n&#8217;ai pas confiance dans les barbus pour créer des choses user friendly. Et moi, j&#8217;aime ça, le code accessible. Fuck la pureté.</p>
<p>Si vous voulez des trucs tarabiscotés, Lisp le fera très bien.</p>
<p>Mais ce n&#8217;est pas Lisp qui a autant de succès, c&#8217;est Python. Et vous savez pourquoi ?</p>
<p>Parce qu&#8217;il est productif, facile, lisible, et avec une énorme communauté pleine de diversité car il est accessible à tout ce monde.</p>
<p>Bref, vous l&#8217;avez compris, je suis contre faire de Python un langage purement fonctionnel si c&#8217;est au prix de tout cela.</p>
<p>Maintenant, il existera peut être des moyens techniques pour rendre des implémentations d&#8217;outils fonctionnels aussi performants et lisibles que leurs versions non fonctionnelles.</p>
<p>Ca a été le cas avec les intensions : de longues chaines de <code>map()</code> et <code>filter()</code> illisibles deviennent claires avec une belle intension. Et c&#8217;est clairement un gain par rapport au <code>for</code> + <code>append()</code> traditionnel. Mais pour les cas moins simple, on a toujours la possibilité d&#8217;utiliser cette méthode, qui est facile à lire, à comprendre et à débugger.</p>
<p>Je gage qu&#8217;un compromis intelligent, voire carrément malin, puisse être trouvé en la matière.</p>
<p>Mais s&#8217;il vous plait, ne cassez pas Python juste pour avoir un nouveau jouet, vous scierez la branche sur laquelle nous sommes tous assis en train de boire l&#8217;apéro en rigolant.</p>
<p>C&#8217;est un reproche qui a été fait au type hinting : si on offre cette possibilité, elle sera utilisée, et tout code avec ces annotations est significativement plus moche. Si demain la majorité des projets en font un pré-requis, beurk.</p>
<p>Je ne pense pas que ça arrivera car c&#8217;est un sacré effort supplémentaire de les écrire. Donc on le fera uniquement si ça vaut le coup : par exemple un gros projet ou une lib avec une bonne base d&#8217;utilisateur.</p>
<p>Ce n&#8217;est pas le cas pour la programmation fonctionnelle : son coût d&#8217;écriture est beaucoup plus bas que celui de la relecture. On paie plus tard. Et ça les gens ne savent pas gérer. L&#8217;humain est naze pour investir dans le futur, c&#8217;est pour ça que nous consommons les ressources de notre planète comme des goinfres, qu&#8217;on pollue à foison et qu&#8217;on laisse des dirigeants voter des lois liberticides.</p>
<h2>Bonnes pratiques</h2>
<p>Bien que je suis clairement en faveur de mettre un frein à l&#8217;enthousiasme des programmeurs FP tant qu&#8217;un terrain d&#8217;entente intelligent ne sera pas trouvé, ça ne veut pas dire qu&#8217;on ne peut pas bénéficier de leurs propositions.</p>
<p>En effet, sachez que vous serez un meilleur programmeur, et que votre programme gagnera en qualité, si vous appliquez quelques principes de programmation fonctionnelle et utilisez les outils déjà existant en Python pour en tirer parti.</p>
<p>Le tout est de ne pas en abuser, et surtout, de ne pas s&#8217;interdire de pondre un code bête et simple quand c&#8217;est plus rapide ou plus clair.</p>
<p>D&#8217;abord, limiter les effets de bord est toujours une bonne chose.</p>
<p>Si vous vous trouvez à modifier une structure de données dans une fonction alors qu&#8217;elle l&#8217;a reçue en paramètre, réfléchissez à deux fois. Est-ce vraiment nécessaire ? Ne pouvez-vous pas faire autrement. A part pour quelques cas très précis (tri sur place, passes multiples, cache, etc), il rare d&#8217;avoir à le faire.</p>
<p>Utilisez les intensions et les générateurs. Utilisez <code>itertools</code>. Utilisez <code>functools</code>. Ces outils demandent un peu d&#8217;apprentissage, mais ils sont formidables : plus performants, plus expressifs, plus lisibles.</p>
<p>Il vous faudra un peu de pratique pour trouver un bon équilibre. Arrive un point où on les utilise partout, ce qui rend le debuggage plus difficile. Passé ce stade, revenez en arrière, calmez-vous, respirez, retourner à l&#8217;impératif, ce n&#8217;est pas non plus retourner au visual basic.</p>
<p>Quand vous faites de la programmation concurrente, voyez si vous ne pouvez pas isoler vos états derrière des services, et faites communiquer les services entre eux via des messages immutables. Votre application sera plus claire, plus stable.</p>
<p>D&#8217;une manière générale, il est bon de diviser son code en petites unités, fonctionnelles justement, qui se passent des valeurs les unes aux autres.</p>
<p>Mais au final, n&#8217;oubliez pas la définition d&#8217;un bon code :</p>
<ul>
<li>Ca marche.</li>
<li>Ca continue de marcher.</li>
<li>On comprend pourquoi ça marche.</li>
</ul>
<p>Le reste n&#8217;est que drosophilie sodomite.</p>


feed_id: http://sametmax.com/?p=16157
title: Est-ce que cet outil existe en Python ? 12
uri: Est-ce-que-cet-outil-existe-en-Python
url: http://sametmax.com/est-ce-que-cet-outil-existe-en-python/
content:
<p>Le test unitaire le plus simple, c&#8217;est de vérifier que son API publique n&#8217;a pas changé.</p>
<p>Ça veut dire :</p>
<ul>
<li>vérifier que les modules ont bien les mêmes définitions (un nom qui était importable n&#8217;a pas disparu).</li>
<li>vérifier que les fonctions et méthodes ont bien la même signature (les arguments avec le même nom n&#8217;ont pas changé de place, et les keywords arguments n&#8217;ont pas changé de nom).</li>
<li>vérifier que les classes ont le même nom, les mêmes méthodes publiques avec les mêmes signatures et les mêmes attributs.</li>
</ul>
<p>Ce sont des tests super cons qui demandent d&#8217;écrire du code du genre :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">class</span> Foo:
    bar <span style="color: #66cc66;">=</span> <span style="color: #008000;">True</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: #66cc66;">,</span> stuff<span style="color: #66cc66;">=</span><span style="color: #008000;">False</span><span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>.<span style="color: black;">stuff</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> thing<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: #483d8b;">&quot;doh&quot;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># et dans les tests</span>
<span style="color: #008000;">self</span>.<span style="color: black;">assertTrue</span><span style="color: black;">&#40;</span><span style="color: #008000;">hasattr</span><span style="color: black;">&#40;</span>Foo<span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'bar'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #008000;">self</span>.<span style="color: black;">assertTrue</span><span style="color: black;">&#40;</span><span style="color: #008000;">hasattr</span><span style="color: black;">&#40;</span>Foo<span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'thing'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #008000;">self</span>.<span style="color: black;">assertTrue</span><span style="color: black;">&#40;</span><span style="color: #008000;">hasattr</span><span style="color: black;">&#40;</span>Foo<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'stuff'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Et personne ne le fait, car déjà les tests c&#8217;est relou, mais écrire des tautologies à la main, c&#8217;est au dela du tolérable.</p>
<p>Pourtant, ce genre de tests m&#8217;aurait déjà sauvé les gosses plusieurs fois. Une faute de frappe qui se glisse, un attribut qu&#8217;on rend privé, un méthode qu&#8217;on déplace et on pense avoir tout refactoré, un pote qui change un truc qu&#8217;on utilisait, etc.</p>
<p>Je me demandais donc si il existait un truc qui permette de faire :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #008000;">self</span>.<span style="color: black;">assertStablePublicAPI</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;package.module&quot;</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># scanne tout le module et tous les objets</span>
<span style="color: #008000;">self</span>.<span style="color: black;">assertStablePublicAPI</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;package.module:Class&quot;</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># check juste la classe</span>
<span style="color: #008000;">self</span>.<span style="color: black;">assertStablePublicAPI</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;package.module:func&quot;</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># check juste la function</span></pre></td></tr></table></div>

<p>Le but étant que quand on lance les test, ça check si ça rencontre un nouvel objet/attribut/param et sauvegarde tout un dans un JSON. Aux prochains tests, si on a modifier l&#8217;API publique, le test foire jusqu&#8217;à ce qu&#8217;on modifie explicitement le fichier JSON.</p>
<p>On doit bien entendu pouvoir régler le truc pour ignorer ou ajouter explicitement des choses à checker, par exemple par défaut ça ignore tous les machins avec des underscores dans le nom.</p>
<p>J&#8217;ai cherché sur le net, mais j&#8217;arrive pas à trouver ça. Des pistes ?</p>


feed_id: http://sametmax.com/?p=16175
title: Pourquoi obliger le SSL par défaut est une grosse connerie 36
uri: Pourquoi-obliger-le-SSL-par-défaut-est-une-grosse-connerie-19-Rece
url: http://sametmax.com/pourquoi-obliger-le-ssl-par-defaut-est-une-grosse-connerie/
content:
<p>Chrome et Mozilla <a href="https://blog.mozilla.org/security/2015/04/30/deprecating-non-secure-http/">parlent</a> de limiter les fonctionnalités de leurs navigateurs sur les sites qui n&#8217;utilisent pas SSL.</p>
<p>Sur le papier, c&#8217;est pavé de bonnes intentions : forcer les auteurs de sites à chiffrer la communication entre le serveur et le client. Plus de sécurité pour les utilisateurs, tant pis pour les dev paresseux, pas vrai ?</p>
<p><strong>Sauf que HTTPS fonctionne sur le principe d&#8217;autorités centrales</strong>. Vous devez obtenir un certificat auprès d&#8217;une autorité de confiance, sans quoi le navigateur va afficher ça :<br />
<div id="attachment_16176" style="width: 700px" class="wp-caption aligncenter"><a href="media/a4d75434.firefoxCertError.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2015/05/firefoxCertError.jpg" class="grouped_elements" rel="tc-fancybox-group16175"><img src="media/a4d75434.firefoxCertError.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2015/05/firefoxCertError.jpg" alt="This connection is untrusted" width="690" height="431" class="size-full wp-image-16176" /></a><p class="wp-caption-text">Michou ne va pas lire ce texte, encore moins chercher et trouver comment accéder au site. Elle va courir. Un virus !</p></div></p>
<p>Les moteurs de recherche vont vous plomber, l&#8217;utilisateur va fuir, bref, votre site est mort.</p>
<p>Et c&#8217;est la que ça devient fun, car les autorités centrales sont des organismes privés, et il n&#8217;y en a pas beaucoup. Ils ne sont pas tenus de vous filer un certificat, et peuvent le retirer à tout moment. </p>
<p>En clair, <strong>forcer SSL partout, c&#8217;est donner la main à quelques grosses boites pour décider qui a le droit d&#8217;être sur le Web ou pas.</strong> Vous voulez faire un truc qui ne leur plait pas ? Attention, montrer un tableau classique avec des nichons ne plait pas à Apple, faire un noeud Tor ne plait pas à Amazon, les bitcoins ne plaisent pas à Paypal et être gay ne plait pas à plein de gouvernements.</p>
<p>Toutes ces entités travaillent main dans la main avec les autorités de certification, et avoir Mozilla en <a href="https://letsencrypt.org/">proposer</a> une n&#8217;y changera rien. Si vous faites un truc que ces gens ne veulent pas, vous effacer du Web sera aussi facile que de faire pression pour révoquer votre certificat.</p>
<p>Sans jugement. Sans procès. Sans recours possible.</p>
<p>Le Web deviendra un app store.</p>
<p>EDIT : </p>
<p>Je rajoute mon commentaire sur let&#8217;s encrypt ici sinon je sens que tout le monde va radoter</p>
<blockquote><p>L’article a un lien qui pointe vers let’s encrypt. Ca ne change rien : c’est centralisé, privé, et subira des pressions comme tous les autres. J’aime Mozilla, j’ai confiance en eux, mais ils n’ont aucun moyen de garantir la neutralité de let’s encrypt, ne serait que par rapport aux gouvernements.</p>
<p>Et puis quoi ? A la fin tous les sites “border line” seront chez eux ? Comme ça bam, un bon single point of failure à attaquer pour tout faire tomber d’un coup ?</p>
<p>FBI. FBI. FBI.</p></blockquote>


feed_id: http://sametmax.com/?p=16187
title: Quels exercices pour débutants en Python ? 40
uri: Quels-exercices-pour-débutants-en-Python-25-Recently-updated
url: http://sametmax.com/quels-exercices-pour-debutants-en-python/
content:
<p>Quand quelqu&#8217;un commence à programmer avec Python, il faut lui apprendre les bases : les conditions, les boucles, les listes, les dicos, les fichiers, les fonctions, les classes et tout le bordel.</p>
<p>Pour que ça rentre, et pour identifier les points à consolider, les exercices sont indispensables.</p>
<p>Malheureusement un bon exercice est très dur à construire :</p>
<ul>
<li>Il faut qu&#8217;il soit suffisamment intéressant pour garder l&#8217;élève en éveil. Découvrir quelque chose, faire un truc qui paraisse un peu utile, etc.</li>
<li>Mais il ne faut pas mélanger trop de notions nouvelles à la fois (et donc on est limité par ce que l&#8217;élève sait).</li>
<li>Si possible, il est bon d&#8217;éviter de se répéter. Or quand on travaille sur des notions connexes (ex: liste et boucle for) ou qu&#8217;on fait un autre exo sur le même thème, c&#8217;est chaud.</li>
</ul>
<p>Il y a des grands classiques : </p>
<ul>
<li>Le jeu &#8220;deviner un nombre&#8221;</li>
<li>Le master mind</li>
<li>La todo list</li>
<li>Calculer le nombre de fois qu&#8217;apparait chaque mot dans dans un texte.</li>
<li>Parcourir tout un tas de fichiers et en trouver un avec une caractéristique particulière.</li>
<li>Déplacer ses fichiers récursivement pour les organiser selon une hiérarchie nom/dossier.</li>
<li>Lire une page web et en extraire une partie.</li>
<li>Parcourir son historique Web Chrome/Firefox et trouver les 5 sites les plus visités.</li>
</ul>
<p>Certains ne sont plus possibles : parcourir l&#8217;API tweeter par exemple est devenu beaucoup trop compliqué alors qu&#8217;avant c&#8217;était un truc super fun à faire faire.</p>
<p>D&#8217;autres sont vachement plus faciles : s&#8217;envoyer un sms d&#8217;alerte si il va pleuvoir aujourd&#8217;hui est un jeu d&#8217;enfant si on est chez free qui a une URL pour ça.</p>
<p>Est-ce que vous avez des exos sympas à proposer ? Je cherche l&#8217;inspiration.</p>
<p>Si vous postez un exo, merci d&#8217;y joindre les notions testées et les pré-requis ainsi que, si nécessaire, le public visé.</p>


feed_id: http://sametmax.com/?p=16208
title: Zerobin passe à Python 3 16
uri: Zerobin-passe-à-Python-3-Recently-updated
url: http://sametmax.com/zerobin-passe-a-python-3/
content:
<p>Ça faisait longtemps que je n&#8217;avais pas touché <a href="https://github.com/sametmax/0bin">0bin</a>, le pastebin chiffré côté client écrit en Python.</p>
<p>Le support de Python 2 devait s&#8217;arrêter en mai 2015, soit ce mois-ci. Cela a été repoussé à 2020, mais pour marquer le coup symboliquement j&#8217;ai porté notre brave bestiole qui supporte maintenant la 2.7 et la 3.4.</p>
<p>Comme je n&#8217;ai jamais pris le temps de faire des tests unitaires sur ce projet, il est possible que j&#8217;ai cassé des trucs. J&#8217;ai testé manuellement, mais bon, on ne sait jamais, je vous avertis avant du danger :)</p>
<p>Le portage a pris une après-midi.</p>
<p>Même si ce n&#8217;est pas l&#8217;affaire de deux minutes, ce n&#8217;est pas non plus la montagne qu&#8217;on s&#8217;en fait. C&#8217;est du boulot, chiant et ingrat (surtout pour supporter 2.x ET 3.x avec une seule base de code), mais pas un travail de titan.</p>
<p>Et en prime, ça me permet de faire un peu reparler du projet qui n&#8217;avait plus eu de mise à jour depuis un bail.</p>
<p>Il mérite d&#8217;ailleurs encore pas mal d&#8217;amour :</p>
<ul>
<li>Y a des issues qui sont toujours en attente sur github (certaines datent d&#8217;un an). Et c&#8217;est parce que je suis une merde procrastinatrice, il faut bien l&#8217;avouer.</li>
<li>Quelques features comme la suppression de l&#8217;histo ou d&#8217;un paste en particulier seraient les bienvenues.</li>
<li>Ca mériterait d&#8217;être porté à Angular. La lasagna jquery, c&#8217;est pas glop.</li>
<li>Un client Python serait pas de refus, et donc une API, et donc une clé API.</li>
<li>Une admin pour ses propres pastes avec URL jetable serait idéale. Mais faudrait changer le format de fichier des pastes, et donc versionner le format, et prévoir la migration des anciens.</li>
<li>Une admin pour les DMCA s&#8217;est faite sentir pas mal de fois.</li>
<li>Un script pour delete un paste en Python aussi.</li>
<li>Et pourquoi pas un packaging sous forme de .deb ou .rpm ?</li>
<li>Le support des bases de données n&#8217;a jamais été implémenté, c&#8217;est triste.</li>
<li>On avait parlé d&#8217;en faire une version avec auto réplication sur ses amis pour éviter la censure.</li>
<li>Et de faire un chat chiffré en dessous.</li>
<li>Et un éditeur de paste collaboratif. Mais faudrait porter zerobin vers crossbar.io.</li>
</ul>
<p>Bref, ce &#8220;petit&#8221; projet a de beaux jours devant lui. Sauf que pour l&#8217;instant, y a une seule limace qui code dessus.</p>
<p>P.S : j&#8217;ai aussi réparé le &#8220;Mail this&#8221;, qui n&#8217;utilise plus l&#8217;URL raccourcie. En effet cette dernière n&#8217;est pas dispo dès qu&#8217;on dépasse le rate de l&#8217;API google, ce qui arrive tous les jours maintenant. La rançon du succès je suppose.</p>


feed_id: http://sametmax.com/?p=16198
title: Pendant ce temps, à Vera Cruz 8
uri: Pendant-ce-temps-à-Vera-Cruz-8-Recently-updated
url: http://sametmax.com/pendant-ce-temps-a-vera-cruz/
content:
<p>Pour une fois, ce n&#8217;est pas un article payé par Tavendo, mais bien un truc que je ponds par enthousiasme :)</p>
<p>Pendant qu&#8217;on en parle pas, la stack WAMP continue d&#8217;évoluer, des mises à jours significatives ayant été apportées à Crossbar.io, ainsi qu&#8217;aux libs Python et JS d&#8217;autobahn. Parmi les plus intéressantes :</p>
<ul>
<li>Le code passe de la licence Apache 2 à la licence MIT, augmentant la compatibilité avec un tas d&#8217;autres licences.</li>
<li>On peut faire un SUB avec un joker, et donc lier un seul callback à plusieurs événements.</li>
<li>On peut faire un register avec un joker également.</li>
<li>On peut choisir la stratégie à appliquer si plusieurs registers sont faits sur le même nom.</li>
<li>Une meta API permet d&#8217;être prévenu quand un client fait quelque chose ou de demander l&#8217;état des nœuds en cours.</li>
</ul>
<p>Inutile de dire que c&#8217;est trop cool.</p>
<p>Pour profiter de tout ça, il suffit de faire :</p>

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

<p>Et de télécharger la nouvelle version de la <a href="https://autobahn.s3.amazonaws.com/autobahnjs/latest/autobahn.min.jgz">dernière version</a> de la lib JS.</p>
<h2>Licence MIT</h2>
<p>Auparavant le travail de Tavendo était essentiellement sous Licence Apache. Une licence libre, certes, mais qui pouvait poser problème quand on mélangeait tout ça avec d&#8217;autres licences (par exemple, elle n&#8217;est pas compatible avec la GPL2). Avec la version 0.10, le code est maintenant sous licence MIT, beaucoup plus permissive.</p>
<h2>Joker pour les subs</h2>
<p>Supposez que vous faites un système de jeu d&#8217;échec donc chaque coup déclenche un événement &#8220;chess.game.[id_de_partie]&#8221;. C&#8217;est pratique, car seuls les clients intéressés à cette partie vont recevoir les événements. Mais si votre serveur doit enregistrer un log de tous les coups d&#8217;une partie, il faut que chaque client envoie AUSSI les coups au serveur explicitement.</p>
<p>C&#8217;était en tout cas vrai avant cette mise à jour, puisque maintenant on peut spécifier <a href="http://crossbar.io/docs/Pattern-Based-Subscriptions/">des jokers</a> dans les noms des topics au moment de l&#8217;abonnement.</p>
<p>Essentiellement il y a deux modes.</p>
<p>Le mode &#8220;prefix&#8221;, qui match tous les events qui commencent par ce nom :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="javascript" style="font-family:monospace;">session.<span style="color: #660066;">subscribe</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;debut.du.nom.du.topic&quot;</span><span style="color: #339933;">,</span> callback<span style="color: #339933;">,</span> <span style="color: #009900;">&#123;</span> match<span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;prefix&quot;</span> <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
# matchera debut.<span style="color: #660066;">du</span>.<span style="color: #660066;">nom</span>.<span style="color: #660066;">du</span>.<span style="color: #660066;">topic</span>.<span style="color: #660066;">genial</span> et debut.<span style="color: #660066;">du</span>.<span style="color: #660066;">nom</span>.<span style="color: #660066;">du</span>.<span style="color: #660066;">topic</span>.<span style="color: #660066;">trop</span>.<span style="color: #660066;">cool</span></pre></td></tr></table></div>

<p>Et le mode &#8220;wildcard&#8221; qui permet, un peu comme les glob Unix (mais on utilise &#8220;..&#8221; au lieu de &#8220;*&#8221;&#8221;), de faire un texte à trou :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="javascript" style="font-family:monospace;">session.<span style="color: #660066;">subscribe</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;nom.du.topic..general&quot;</span><span style="color: #339933;">,</span> callback<span style="color: #339933;">,</span> <span style="color: #009900;">&#123;</span> match<span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;wildcard&quot;</span> <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
# matchera <span style="color: #3366CC;">&quot;nom.du.topic.moins.general&quot;</span> et <span style="color: #3366CC;">&quot;nom.du.topic.oui.mon.general&quot;</span></pre></td></tr></table></div>

<p>Tous les callbacks qui matchent un topic seront appelés.</p>
<h2>Plusieurs clients pour la même procédure</h2>
<p>On peut utiliser le même principe que pour les sub avec joker, mais pour les procédures.</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="javascript" style="font-family:monospace;">session.<span style="color: #660066;">register</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;debut.du.nom.de.la.procedure&quot;</span><span style="color: #339933;">,</span> callback<span style="color: #339933;">,</span> <span style="color: #009900;">&#123;</span> match<span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;prefix&quot;</span> <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>    
session.<span style="color: #660066;">register</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;nom.de.la.procedure..generale&quot;</span><span style="color: #339933;">,</span> callback<span style="color: #339933;">,</span> <span style="color: #009900;">&#123;</span> match<span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;wildcard&quot;</span> <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

<p>La différence avec le subscribe, c&#8217;est que seule UNE procédure est appelée. Dans les cas simples, un match exact prend le dessus sur un prefix (et le plus long prefix gagne toujours), qui prend le dessus sur un wildcard. Crossbar n&#8217;implemente pas encore de résolution pour deux wildcards en conflits, et je ne sais pas ce qu&#8217;il fait dans ce cas.</p>
<p>Il est aussi possible de <a href="http://crossbar.io/docs/Shared-Registrations/">de définir des règles</a> d&#8217;appels en faisant :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="javascript" style="font-family:monospace;">session.<span style="color: #660066;">register</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;nom.de.la.procedure..generale&quot;</span><span style="color: #339933;">,</span> procedure1<span style="color: #339933;">,</span> <span style="color: #009900;">&#123;</span> invoke<span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;regle&quot;</span><span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

<p>La règle peut être :</p>
<ul>
<li><strong>roundrobin</strong>: on prend la liste de clients, on regarde le dernier appelé, et on utilise le suivant.</li>
<li><strong>random</strong>: on prend un client au hasard.</li>
<li><strong>last</strong>: on prend le dernier client ajouté de la liste.</li>
<li><strong>first</strong>: on prend premier client ajouté à la liste.</li>
</ul>
<p>&#8220;roundrobin&#8221; et &#8220;random&#8221; sont pratiques pour faire du load balancing.</p>
<p>&#8220;last&#8221; et &#8220;first&#8221; sont pratique pour les mises à jour d&#8217;un client sans arrêter le serveur. En gros on rajoute un client, on attend un peu, &#8220;last&#8221; route tout sur le dernier client, donc le nouveau client prend les requêtes, et on peut arrêter le vieux clients sans souci. </p>
<h2>Meta RPC</h2>
<p>Crossbar met automatiquement à notre disposition des procédures distantes toutes faites qui donnent des informations sur l&#8217;état des clients et du routeur. Voici les RPC que vous pouvez maintenant faire :</p>
<ul>
<li><strong>wamp.session.list</strong>: lister les sessions des clients connectés au routeur.</li>
<li><strong>wamp.session.get</strong>: obtenir les infos d&#8217;un session pour un ID en particulier.</li>
<li><strong>wamp.session.count</strong>: obtenir le nombre de client connectés.</li>
<li><strong>wamp.registration.lookup</strong>: absolument aucune idée.</li>
<li><strong>wamp.registration.get</strong>: obtenir des infos sur une procédure distante enregistrée.</li>
<li><strong>wamp.registration.list_callees</strong>: lister les clients ayant enregistré pour une procédure avec ce nom.</li>
<li><strong>wamp.registration.count_callees</strong>: compter les clients ayant enregistré une procédure avec ce nom.</li>
<li><strong>wamp.registration.list</strong>: lister toutes les procédures distantes disponibles.</li>
<li><strong>wamp.registration.remove_callee</strong>: virer un client de la liste de des clients enregistrés pour cet procédure.</li>
<li><strong>wamp.subscription.lookup</strong>: toujours aucune idée.</li>
<li><strong>wamp.subscription.get</strong>: récupérer des infos sur l&#8217;abonnement avec cet ID.</li>
<li><strong>wamp.subscription.list_subscribers</strong>: lister les clients qui sont abonnés à ce sujet.</li>
<li><strong>wamp.subscription.count_subscribers</strong>: compter les clients abonnés à ce sujet.</li>
<li><strong>wamp.subscription.match</strong>: aucune idée.</li>
<li><strong>wamp.subscription.list</strong>: lister tous les sujets d&#8217;abonnement disponibles.</li>
<li><strong>wamp.subscription.remove_subscriber</strong>: </li>
<p> virer un client de la liste des abonnés à ce sujet.</ul>
<p>En gros, si vous voulez faire une admin qui vous permet de killer certains client ou rechercher si des events existent, vous utilisez ça.</p>
<h2>Meta SUB</h2>
<p>De même, le routeur envoie maintenant des publications sur des sujets concernant le cycle son cycle de vie et celui des clients. On peut donc s&#8217;abonner à ces meta topic pour réagir à l&#8217;activité de son système :</p>
<ul>
<li><strong>wamp.session.on_join</strong> : un client s&#8217;est connecté au routeur.</li>
<li><strong>wamp.session.on_leave</strong> : un client s&#8217;est déconnecté du routeur.</li>
<li><strong>wamp.subscription.on_create</strong> : un nouveau topic existe.</li>
<li><strong>wamp.subscription.on_subscribe</strong> : un client s&#8217;est abonné à un topic.</li>
<li><strong>wamp.subscription.on_unsubscribe</strong> : un client s&#8217;est désabonné à un topic.</li>
<li><strong>wamp.subscription.on_delete</strong> : un topic est retiré de la liste des topics disponibles.</li>
<li><strong>wamp.registration.on_create</strong> : une procédure distante porte ce nom pour la première fois.</li>
<li><strong>wamp.registration.on_register</strong> : un client propose ajoute un callable pour ce nom de procédure distante..</li>
<li><strong>wamp.registration.on_unregister</strong> : un client retire son callable pour ce nom de procédure distante. </li>
<li><strong>wamp.registration.on_delete</strong> : le nom de cette procédure n&#8217;a plus aucun callable lié.</li>
<li><strong>wamp.schema.on_define</strong> : aucune idée.</li>
<li><strong>wamp.schema.on_undefine</strong> : kamolox. </li>
</ul>
<p>Ce genre de truc est idéal pour faire un petit outil de monitoring pour son archi et voir ce qui se passe en temps réel.</p>
<h2>Le HTTP bridge est complet</h2>
<p>Le <a href="http://crossbar.io/docs/HTTP-Bridge-Services/">bridge HTTP</a> propose maintenant PUB/SUB, et tout RPC. On peut donc maintenant utiliser crossbar depuis n&#8217;importe quel app qui peut faire du HTTP : flask, pyramid, ruby on rails, du PHP pur, wget en ligne de commande et tout le bordel. C&#8217;est plus verbeux, mais ça dépanne bien.</p>


feed_id: http://sametmax.com/?p=16221
title: Je n’expliquerai plus les CBV 17
uri: Je-n-expliquerai-plus-les-CBV-7-Recently-updated
url: http://sametmax.com/je-nexpliquerai-plus-les-cbv/
content:
<p>Les <a href="http://sametmax.com/des-vues-normales-aux-vues-generiques-django/">Class Based Views</a> sont des vues génériques réutilisables qui permettent de faire automatiquement des tâches courantes dans Django comme :</p>
<ul>
<li>Récupérer et afficher une ou plusieurs entrées en base de données.</li>
<li>Afficher et valider un formulaire.</li>
<li>Faire un mix des deux pour modifier des entrées en base.</li>
</ul>
<p><a href="http://sametmax.com/des-annees-plus-tards-je-naime-toujours-pas-les-cbv/">Je ne les ai jamais aimées</a>. Avant, les vues génériques étaient sous forme de fonction, simples, pratiques, c&#8217;était parfait. Et ça a été retiré du framework pour des versions OO sous prétexte que c&#8217;était plus flexible.</p>
<p>Maintenant, ce sont ces gros tas immondes, avec un ordre d&#8217;appel de méthodes complexes, des mixins dans tous les sens et une chaine d&#8217;héritage velue. </p>
<p>Je pense que c&#8217;est une bonne occasion pour rappeler que la POO n&#8217;est pas faite pour être utilisée partout, tout le temps. Aucun putain de paradigme de programmation n&#8217;est fait pour être utilisé partout, tout le temps. C&#8217;est pour ça qu&#8217;il y en a plusieurs.</p>
<p>Dans notre cas des CBV, la conséquence est que c&#8217;est <a href="http://sametmax.com/explication-de-code-des-mixins-et-des-decorateurs-de-methode-pour-django/">un enfer</a> pour expliquer tout usage qui ne soit pas un hello world, ce que la doc se garde bien de faire.</p>
<p>Après il y a toujours un malin pour dire &#8220;mais si tu vois tu fais ça, et ça, ça prend 5 lignes, c&#8217;est pas si dur&#8221;. Ouai, maintenant va expliquer ça à un stagiaire, et donne lui un exercice avec une form view qui doit modifier un objet, le lier à un user seulement si il a la permission de le faire. Juste pour voir en combien de temps il trouve. Je vais en WE à Barcelone en attendant. Je prévoie une extension à Rome pour quand il devra relire son code le trimestre prochain.</p>
<p>Et si encore c&#8217;était pour un gain de productivité évident, je fermerais les yeux. Mais c&#8217;est pas le cas. Même moi qui sait utiliser ces&#8230; ces choses&#8230; je dois regarder dans la doc à chaque fois que j&#8217;en utilise une. Et ensuite quand je relis mon code quelques mois plus tard, je chope de pattes d&#8217;oies aux coins des yeux.</p>
<blockquote><p>If you have to refer to the documentation every time you use a module, find (or build) a new module.</p></blockquote>
<p>Dixit Kenneth Reitz, le mec qui a pondu <a href="https://github.com/kennethreitz/requests">requests</a>. Donc on va user something else que les CBV, si vous le voulez bien.</p>
<p>Un lecteur m&#8217;a (encore) pointé du doigt qu&#8217;un schéma du MRO et de l&#8217;ordre d&#8217;appel des méthodes serait utile. Vous vous rendez compte du truc ? On peut comprendre l&#8217;ORM sans schéma alors que c&#8217;est une machine de guerre, et il faut une carte pour comprendre comment faire un listing un peu custo avec une CBV ? J&#8217;ai évalué la somme de travail pour faire ledit schéma, et elle est énorme : trop de classes, trop de méthodes, trop de subtilités.</p>
<p>Bref, je jette le tablier, fuck les CBV. Je ne les inclurai plus dans mes formations, mes tutos, mes aides sur les forums, etc.</p>


feed_id: http://sametmax.com/?p=16231
title: Python 3 est fait pour les nouveaux venus 19
uri: Python-3-est-fait-pour-les-nouveaux-venus-10-Recently-updated
url: http://sametmax.com/python-3-est-fait-pour-les-nouveaux-venus/
content:
<p>&#8220;Je n&#8217;ai pas vraiment de raison de migrer vers Python 3&#8243; est la cause numéro 1 de la lente migration de Python 2 vers 3. <a href="http://astrofrog.github.io/blog/2015/05/09/2015-survey-results/">16% utilisent Python 3 comme VM principale</a>, contre 81% pour 2.7 (on notera la part ridicule des autres versions, que vous pouvez donc ignorer dans le support de vos libs). Le report de la dépréciation de Python 2 de 2015 à 2020 a donc tout son sens : la communauté a pris son temps car le jeu n&#8217;en valait pas la chandelle.</p>
<p>Mais on y arrive. La plupart des libs importantes <a href="http://python3wos.appspot.com/">sont portées</a>, les hostings supportent beaucoup mieux Python 3, même le portage de twisted <a href="https://twistedmatrix.com/trac/milestone/Python-3.x">a repris</a>, <a href="http://twistedmatrix.com/pipermail/twisted-python/2015-May/029481.html">grace à Crossbar d&#8217;ailleurs</a> :) Perso je commence toujours mes nouveaux projets en Python 3.</p>
<p>On peut le dire maintenant, tout le monde a eu un peu peur. D&#8217;ailleurs <a href="https://www.youtube.com/watch?feature=player_detailpage&#038;v=VhCsOwzRgyc#t=472">Guido n&#8217;est pas prêt de recommencer</a>. Après PHP 6 et Perl 6 qu&#8217;on attend toujours, des ralages dans tous les sens, des version 3.0, 3.1 et 3.2 vraiment à chier, après le retrait de <code>%</code> pour les bytes et l&#8217;appel pour une 2.8, on s&#8217;est tous demandé si ça allait pas foirer. </p>
<p>Maintenant, je suis certain que non. On a passé cette étape, ça a pris du temps, ça a fait mal au cul, mais pendant que Node <a href="https://twitter.com/sam_et_max/status/595495925541404672">se divise en 3 versions</a> alors qu&#8217;il existe depuis à peine 6 ans, Python fête ses 20 ans avec une seule transition difficile, qui s&#8217;est révélée gagnante.</p>
<p>Mais gagnante pour qui ?</p>
<p>C&#8217;est vrai qu&#8217;il y a de bonnes features qui ne sont qu&#8217;en version 3 : <a href="https://docs.python.org/3/library/asyncio.html">asyncio</a>, <a href="https://docs.python.org/3/library/pathlib.html">pathlib</a>, <a href="https://docs.python.org/3/library/statistics.html">statistics</a>, <a href="https://docs.python.org/3/library/ipaddress.html">ipaddress</a>, <a href="https://docs.python.org/3/library/enum.html">enums</a>, <a href="https://docs.python.org/dev/library/lzma.html">lzma</a>, <a href="http://stackoverflow.com/questions/24752395/python-raise-from-form-usage">raise from</a>, <a href="https://www.python.org/dev/peps/pep-0380/">yield from</a>, <a href="https://docs.python.org/3/library/functools.html#functools.singledispatch">singledispatch</a>, <a href="https://docs.python.org/2/library/multiprocessing.html">multiprocessing.Pool.map</a>, <a href="https://www.python.org/dev/peps/pep-0465/">@</a>, <a href="http://sametmax.com/async-await-la-feature-de-derniere-minute-de-python-3-5/">await/async</a>, les <a href="http://sametmax.com/point-rapide-sur-les-types-hints/">type hints</a>, le <a href="http://stackoverflow.com/questions/1261875/python-nonlocal-statement">support avancé des closures</a> et <a href="http://www.reddit.com/r/Python/comments/2x8d64/pep_448_additional_unpacking_generalizations/">l&#8217;unpacking étendu</a>. Mais d&#8217;abord, certaines arrivent pour la 3.5, ensuite, les autres n&#8217;ont visiblement pas motivé les vieux de la vieille à faire le pas pendant 5 ans. </p>
<p>Pourquoi ? Parce que Python 3 n&#8217;a pas été créé pour eux. Il a été créé pour les nouveaux arrivants dans le langage.</p>
<p>Ayant un peu d&#8217;expérience avec le fait d&#8217;enseigner Python, je peux vous dire que faire passer Python 2 et Python 3, c&#8217;est le jour et la nuit :</p>
<ul>
<li>Le texte marche automatiquement la plupart du temps : on a des objets unicodes partout, utf8 est par défaut, <code>os.truc</code> retourne de l&#8217;unicode, <code>open</code> a un paramètre <code>encoding</code> et mettre &#8220;é&#8221; dans un <code>print</code> ou un commentaire marche out of the box. Ca change la vie.</li>
<li>Le corolaire est qu&#8217;il y a plein de truc en moins à expliquer. <code>u</code>, <code>from __future__</code>, <code># coding</code> mais aussi <code>object</code> et mon favori : <code>super()</code> et non <code>super(ClassName, self)</code>. Franchement même moi ça me perturbe de taper ça.</li>
<li><code>print()</code> n&#8217;est pas un cas particulier : écrire sur <code>stderr</code>, éviter un saut de ligne et séparer des entrées sont juste des paramètres de fonctions et non des <code>&gt;&gt;</code> et <code>,</code>.</li>
<li>Les noms des modules de la stdlib sont cohérents. On peut les deviner, les découvrir et chercher de la doc plus facilement.</li>
<li>La hiérarchie des exceptions est beaucoup plus claire. <code>IOError/OSError</code> ont des enfants qui évitent l&#8217;obscure usage de <code>errno</code>.</li>
<li>Par ailleurs plein de messages d&#8217;erreurs sont plus explicites.</li>
<li>Et des nouveaux messages d&#8217;erreur font leur apparition. On ne peut plus faire <code>True = reponse</code> ou <code>2 > "1"</code>. Cette dernière, TOUT LE MONDE me l&#8217;a faite.</li>
<li>Les pyc sont groupés dans un dossier. Tellement plus clair.</li>
<li>Le shell Python a l&#8217;autocompletion activée. </li>
<li><code>/</code> est moins surprenant. Encore un truc de moins à expliquer.</li>
<li>&#8220;There is one way to do it&#8221;. Plus de <code>range</code> vs <code>xrange</code>, <code>__str__</code> vs <code>__unicode__</code>, <code>str()</code> vs <code>bytes</code> vs <code>unicode</code>, <code>int()</code> vs <code>long()</code>, <code>dict.items</code> vs <code>iteritems</code> vs <code>viewitems</code>, <code>input()</code> vs <code>raw_input().</code>&#8230; Est-ce que vous voyez la somme de choses en moins à apprendre ? C&#8217;est colossale. Et plein de sources d&#8217;erreurs en moins. Par exemple, <code>input()</code> en Python 2 déclenche <code>NameError</code> quand on saisie des lettres. C&#8217;est super marrant, je vous raconte pas.</li>
<li>Les imports sont toujours absolus. Combien de fois j&#8217;ai du dire &#8220;alors, tu as appelé ton module test.py, et ça peut pas marcher parce que&#8230;&#8221;.</li>
<li>Ne pas avoir à dire &#8220;nan, tu peux pas utiliser <code>return</code> si tu utilises <code>yield</code> parce que&#8230; heu&#8230; c&#8217;est comme ça&#8221;.</li>
<li>Et tous ces bugs qui arrivent parce que quelque part, l&#8217;apprenant a utilisé une old style class dans la hierarchie et on passe 20 minutes à essayer comprendre un comportement aberrant pendant que le reste de la classe est sur facebook.</li>
<li> Les variables ont une portée limitée dans les compréhensions :

<div class="wp_syntax"><table><tr><td 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> <span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">3</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">5</span><span style="color: black;">&#93;</span>:
    squared <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span>x**<span style="color: #ff4500;">2</span> <span style="color: #ff7700;font-weight:bold;">for</span> x <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">2</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">3</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">4</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span>
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>x<span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Affiche 1, 3, 5 en Python 3, 4 4 4 en Python 2. Certes, j&#8217;essaye d&#8217;apprendre à mes élèves à faire gaffe aux noms de variables, mais bon, y en a toujours un qui chie dans la colle, faut pas se leurrer.
</li>
</ul>
<p>Nous, utilisateurs chevronnés de la 2.7, ne nous rendons pas compte de la somme de connaissance que nous avons accumulé au fil des années pour contourner ces problèmes. Les nouveaux, même autodidactes, vont aller beaucoup plus vite.</p>
<p>Python 3 fait très bien son boulot : garder Python sa place de meilleur langage pour l&#8217;apprentissage. Ca tombe bien, parce qu&#8217;un fois appris, il sert aussi à plein de choses professionnellement, et pas juste du dev Web (ruby), du sysadmin (perl) ou des maths (R).</p>
<p>Et du coup la migration a pris du temps.</p>
<p>Depuis la 3.4, tout s&#8217;accélère. L&#8217;investissement est en train de payer.</p>
<p>Perso, quand je dois écrire du Python 2 maintenant, ça me fait râler :)</p>


feed_id: http://sametmax.com/?p=16249
title: Le don du mois : Vasalgel 2
uri: Le-don-du-mois-Vasalgel
url: http://sametmax.com/le-don-du-mois-vasalgel/
content:
<p>Il n&#8217;y a pas de date pour le don du mois, ça part quand ça me prend.</p>
<p>Aujourd&#8217;hui l&#8217;inspiration s&#8217;est présentée sous la forme d&#8217;une newsletter que je reçois régulièrement à propos de couilles de babouins. Si, si.</p>
<p>Souvenez-vous, <a href="http://sametmax.com/la-quete-de-la-contraception-masculine/">je suis l&#8217;avancée du projet RISUG</a>, un contraceptif masculin semi-permanent et non hormonal.</p>
<p>Le concept est indien, mais la <a href="https://www.parsemusfoundation.org/vasalgel-home/">Parmesus Foundation essaye d&#8217;importer le procédé</a> aux USA. Ca veut dire une batterie de tests à faire, l&#8217;approbation auprès des autorités, etc.</p>
<p>La fondation se présente avec ce but :</p>
<blockquote><p>Advance innovative medical research and develop low-cost solutions that are neglected by the pharmaceutical industry.</p></blockquote>
<p>C&#8217;est peut être du bullshit (&#8220;écrivez à l&#8217;arc&#8221; :)), et franchement difficile de m&#8217;assurer que mon argent ne finira pas dans les poches d&#8217;un business angel peu scrupuleux.</p>
<p>Mais personnellement, je suis prêt à payer très cher pour éviter toute forme de contraception contraignante tout en ayant la certitude de ne pas avoir d&#8217;enfants.</p>
<p>Du coup, je soutiens l&#8217;initiative, qui par ailleurs <a href="https://parsemusfoundation.secure.nonprofitsoapbox.com/donate">accepte les bitcoins</a>. 0.25BTC partent donc dans leur poche, et je croise les doigts. Un jour peut être, je pourrai faire un saut à JFK pour faire brider mes nageurs.</p>


feed_id: http://sametmax.com/?p=16275
title: Pourquoi il est difficile de “juste ajouter un nouveau mot clé” 11
uri: Pourquoi-il-est-difficile-de-juste-ajouter-un-nouveau-mot-clé
url: http://sametmax.com/pourquoi-il-est-difficile-de-juste-ajouter-un-nouveau-mot-cle/
content:
<p>Avec les types hints, beaucoup ont suggéré l&#8217;ajout de nouveaux mots clés pour déclarer les types des paramètres et des variables. Guido a refusé, au moins pour les paramètres des fonctions, et s&#8217;en tient aux annotations.</p>
<p>Mais pourquoi être si têtu ? Après tout, c&#8217;est forward compatible, n&#8217;est-ce pas ?</p>
<p>Faux.</p>
<p>Quand on rajoute un mot clé, on ne peut plus l&#8217;utiliser comme nom de variable, et donc tout code qui utilise une variable qui porte ce nom va planter quand il passera à cette version de Python.</p>
<p>Inutile de dire qu&#8217;un mot clé doit être court et explicite, et que tous les mots courts et explicites sont utilisés comme noms de variables quelque part.</p>
<p>C&#8217;est pour cette raison que l&#8217;ajout de <code>async</code>/<code>await</code> a lancé toute une discussion sur la manière de changer la grammaire.</p>
<p>Et vous savez ce qui a été décidé ? </p>
<p>De ne PAS interdire de faire :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">async <span style="color: #66cc66;">=</span> await <span style="color: #66cc66;">=</span> <span style="color: #008000;">True</span>
async <span style="color: #ff7700;font-weight:bold;">def</span> foo<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    await bar
<span style="color: #808080; font-style: italic;"># pas de SyntaxError</span></pre></td></tr></table></div>

<p>En clair, le parseur va détecter des cas particuliers pour ces instructions dans lesquelles il les identifie comme mot clés, et autoriser quand même leur usage comme variable dans tous les autres cas.</p>
<p>C&#8217;est un compromis pour garder la compatibilité ascendante, mais un compromis qui non seulement introduit un cas particulier dans le code du parseur (beurk), mais en plus permet d&#8217;écrire un code qui avant n&#8217;était pas permis, rendant le langage un peu moins cohérent. Un changement que maintenant on va se trainer pour les releases à venir, qui ouvre un précédent pour les futures débats, qui peut potentiellement s&#8217;accumuler avec d&#8217;autres changement futurs&#8230;</p>
<p>Faire évoluer un langage qui a 20 ans et dont il y a des millions de lignes de code partout, c&#8217;est dur. Chaque petite modification peut entrainer des conséquences importantes, et tout juste milieu renferme des craquelures d&#8217;inélégance.</p>
<p>C&#8217;est aussi pour ça qu&#8217;il est si plaisant d&#8217;inventer son langage, son framework, son outil pour faire x mieux que le status quo y. Il est parfait. Il est tout frais. Personne ne l&#8217;utilise. Il n&#8217;a encore eu aucune cicatrice.</p>
<p>A l&#8217;inverse, garder le cap malgré les remous, maintenir une diète saine et un équilibre mais accepter les saloperies qui passent de temps en temps, ça c&#8217;est difficile. Je suis épaté que Python soit resté si propre avec tout ce qui lui est arrivé au fil des années, et c&#8217;est grâce Guido qui a su dire NON à tout un tas de petits détails qui ne paraissaient pas importants, mais qui cumulés sur 2 décennies auraient transformé le langage en créature fantasque.</p>
<p>Pourvu qu&#8217;ça dure.</p>


feed_id: http://sametmax.com/?p=16268
title: Un ptit post pour remercier tous les contributeurs 32
uri: Un-ptit-post-pour-remercier-tous-les-contributeurs-10-Recently-upda
url: http://sametmax.com/un-grand-merci/
content:
<p>Après ces quelques années de blogging je voulais remercier, et je pense pouvoir parler aussi au nom de Sam,  tous ceux qui ont participé à la joie et la bonne humeur de ce blog.</p>
<p>Mais aussi à l&#8217;évolution d&#8217;IndexError où nous pouvons voir chaque jour avec un très grand plaisir des contributeurs aider sans critiquer ou juger, apporter des réponses ou donner des pistes sans rien demander en échange.</p>
<p>Merci à vous tous de donner de votre (précieux) temps pour aider votre &#8220;prochain&#8221; programmeur. La vitesse des réponses sur IndexError est tout juste hallucinante malgré la &#8220;petite&#8221; communauté.</p>
<p>De plus les commentaires sur le Blog sont toujours courtois et intéressants.</p>
<p>Je remercie en particulier pour IndexError, pour le Blog ça serait trop long à lister (mais j&#8217;en oublie certainement):</p>
<p>Foxmask, boblinux, jc, cOda, doublenain, furankun, Hawke et bien d&#8217;autres&#8230;</p>
<p>Aller je vais aux putes, ce post m&#8217;a épuisé.</p>
<p>Passez un bon Noël!</p>


feed_id: http://sametmax.com/?p=16281
title: Un gros guide bien gras sur les tests unitaires en Python, partie 5 7
uri: Un-gros-guide-bien-gras-sur-les-tests-unitaires-en-Python-partie-5-1
url: http://sametmax.com/un-gros-guide-bien-gras-sur-les-tests-unitaires-en-python-partie-5/
content:
<p>Vous avez <a href="http://sametmax.com/un-gros-guide-bien-gras-sur-les-tests-unitaires-en-python-partie-4/">vu</a> les modules pour faire les tests, mais dès que vous allez vouloir faire des tests sérieux, vous allez vous heurter à la dure réalité.</p>
<p>La réalité est que pour tester, il vous faut la réalité.</p>
<p>Par exemple, si vous tapez dans une base de données, il vous faut une base de données opérationnelle. Pour tester un téléchargement, il vous faut une connexion internet. Pour tester si votre API fonctionne, il faut lancer un serveur Web.</p>
<p>Autre chose, si votre code appelle un autre code, comment vous assurer que cet appel a bien eu lieu ? Il faudrait aussi un logger pour tous les appels, et si le code n&#8217;est pas le vôtre, c&#8217;est encore plus chiant.</p>
<p>Comme nous savons que les informaticiens sont des grosses larves, il y a forcément une solution, au moins partielle, à ces problèmes. En l’occurrence, on va jouer au docteur, à la dinette, aux cowboys et aux indiens.</p>
<p>Bref, on va jouer à faire semblant.</p>
<p><span class='embed-youtube' style='text-align:center; display: block;'><iframe class='youtube-player' type='text/html' width='1170' height='689' src='http://www.youtube.com/embed/vjncyiuwwXQ?version=3&#038;rel=1&#038;fs=1&#038;showsearch=0&#038;showinfo=1&#038;iv_load_policy=1&#038;wmode=transparent' frameborder='0' allowfullscreen='true'></iframe></span></p>
<h2>Les objets mocks</h2>
<p>Un objet mock, c&#8217;est un objet basé sur le <a href="http://sametmax.com/usages-et-dangers-du-null-object-pattern-en-python/">null object pattern</a> qui sert à faire semblant. Quand on l&#8217;instancie avec n&#8217;importe quoi, ça marche, quand on appelle n&#8217;importe quelle méthode, ça marche et ça renvoie un mock.</p>
<p>Bien entendu, comme les besoins des tests sont un peu plus raffinés que ça, mock fait plus que du null object pattern, et permet :</p>
<ul>
<li>De configurer son API.</li>
<li>De configurer ses sides effects.</li>
<li>De configurer sa valeur de retour.</li>
<li>De monkey patcher un autre objet.</li>
<li>D&#8217;enregistrer tous les appels qu&#8217;on lui fait.</li>
</ul>
<p>Alors évidement, comme ça, je me doute bien que la puissance de l&#8217;outil ne vous frappe pas en face comme le nez au milieu de l&#8217;eureka dans un couloir.</p>
<p>C&#8217;est pour ça qu&#8217;on va passer aux exemples concrets. D&#8217;abord, assurez-vous de pouvoir faire <code>import unittest.mock</code>, qui est dispo depuis Python 3.3. Si ce n&#8217;est pas le cas, <a href="http://sametmax.com/votre-python-aime-les-pip/">l&#8217;installer</a> avec <code>pip install mock</code> vous permettra de l&#8217;importer sous la forme <code>import mock</code>. Le reste, c&#8217;est pareil.</p>
<h2>On dirait que moi je t&#8217;attaque et toi tu meurs pas</h2>
<p>Un objet mock est un <a href="http://sametmax.com/les-trucmuchables-en-python/">callable</a>, c&#8217;est-à-dire qu&#8217;il peut être appelé comme une fonction ou une classe, et il retourne toujours un objet mock :</p>

<div class="wp_syntax"><table><tr><td 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;">unittest</span>.<span style="color: black;">mock</span> <span style="color: #ff7700;font-weight:bold;">import</span> MagicMock <span style="color: #808080; font-style: italic;"># ou from mock import MagicMock</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> mock <span style="color: #66cc66;">=</span> MagicMock<span style="color: black;">&#40;</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>mock<span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&lt;</span>MagicMock <span style="color: #008000;">id</span><span style="color: #66cc66;">=</span><span style="color: #483d8b;">'140302100559296'</span><span style="color: #66cc66;">&gt;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> mock<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&lt;</span>MagicMock name<span style="color: #66cc66;">=</span><span style="color: #483d8b;">'mock()'</span> <span style="color: #008000;">id</span><span style="color: #66cc66;">=</span><span style="color: #483d8b;">'140302101821704'</span><span style="color: #66cc66;">&gt;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> mock<span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span><span style="color: #66cc66;">,</span> <span style="color: #008000;">True</span><span style="color: #66cc66;">,</span> <span style="color: black;">&#91;</span><span style="color: #008000;">Exception</span><span style="color: #66cc66;">,</span> <span style="color: black;">&#123;</span><span style="color: black;">&#125;</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&lt;</span>MagicMock name<span style="color: #66cc66;">=</span><span style="color: #483d8b;">'mock()'</span> <span style="color: #008000;">id</span><span style="color: #66cc66;">=</span><span style="color: #483d8b;">'140302101821704'</span><span style="color: #66cc66;">&gt;</span></pre></td></tr></table></div>

<p>On peut appeler n&#8217;importe quoi sur son objet mock, et ça retourne toujours un objet mock :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> mock.<span style="color: black;">foo</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&lt;</span>MagicMock name<span style="color: #66cc66;">=</span><span style="color: #483d8b;">'mock.foo()'</span> <span style="color: #008000;">id</span><span style="color: #66cc66;">=</span><span style="color: #483d8b;">'140302101723960'</span><span style="color: #66cc66;">&gt;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> mock.<span style="color: black;">nimporte</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>.<span style="color: black;">nawak</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>.<span style="color: black;">je</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>.<span style="color: black;">te</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>.<span style="color: #dc143c;">dis</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&lt;</span>MagicMock name<span style="color: #66cc66;">=</span><span style="color: #483d8b;">'mock.nimporte().nawak().je().te().dis()'</span> <span style="color: #008000;">id</span><span style="color: #66cc66;">=</span><span style="color: #483d8b;">'140302101825744'</span><span style="color: #66cc66;">&gt;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> mock + mock - <span style="color: #ff4500;">10000</span>
<span style="color: #66cc66;">&lt;</span>MagicMock name<span style="color: #66cc66;">=</span><span style="color: #483d8b;">'mock.__add__().__sub__()'</span> <span style="color: #008000;">id</span><span style="color: #66cc66;">=</span><span style="color: #483d8b;">'140302134081520'</span><span style="color: #66cc66;">&gt;</span></pre></td></tr></table></div>

<p>Quand retourner un objet mock n&#8217;est pas possible, l&#8217;objet essaye d&#8217;avoir le comportement qui fera planter le moins possible :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #008000;">int</span><span style="color: black;">&#40;</span>mock<span style="color: black;">&#41;</span>
<span style="color: #ff4500;">1</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: black;">&#91;</span>m <span style="color: #ff7700;font-weight:bold;">for</span> m <span style="color: #ff7700;font-weight:bold;">in</span> mock<span style="color: black;">&#93;</span>
<span style="color: black;">&#91;</span><span style="color: black;">&#93;</span></pre></td></tr></table></div>

<h2>On dirait que le bâton, là, c&#8217;est un sabre laser</h2>
<p>Parfois, néanmoins, il est utile de vouloir avoir un comportement spécifique. Il se trouve que les méthodes des objets mocks peuvent être des objets mocks. Mock, mock, mock !!!!!</p>
<p>Et les objets mocks peuvent être configurés pour avoir un effet de bord ou une valeur de retour :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">mock.<span style="color: black;">you</span> <span style="color: #66cc66;">=</span> MagicMock<span style="color: black;">&#40;</span>side_effect<span style="color: #66cc66;">=</span><span style="color: #008000;">ValueError</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'mofo !'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># un callable marche aussi</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> mock.<span style="color: black;">you</span><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;ipython-input-21-a7e6455585e9&gt;&quot;</span><span style="color: #66cc66;">,</span> line <span style="color: #ff4500;">1</span><span style="color: #66cc66;">,</span> <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #66cc66;">&lt;</span>module<span style="color: #66cc66;">&gt;</span>
    mock.<span style="color: black;">you</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
  File <span style="color: #483d8b;">&quot;/usr/lib/python3.4/unittest/mock.py&quot;</span><span style="color: #66cc66;">,</span> line <span style="color: #ff4500;">885</span><span style="color: #66cc66;">,</span> <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #0000cd;">__call__</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> _mock_self._mock_call<span style="color: black;">&#40;</span>*args<span style="color: #66cc66;">,</span> **kwargs<span style="color: black;">&#41;</span>
  File <span style="color: #483d8b;">&quot;/usr/lib/python3.4/unittest/mock.py&quot;</span><span style="color: #66cc66;">,</span> line <span style="color: #ff4500;">941</span><span style="color: #66cc66;">,</span> <span style="color: #ff7700;font-weight:bold;">in</span> _mock_call
    <span style="color: #ff7700;font-weight:bold;">raise</span> effect
<span style="color: #008000;">ValueError</span>: mofo <span style="color: #66cc66;">!</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> mock.<span style="color: black;">mock</span> <span style="color: #66cc66;">=</span> MagicMock<span style="color: black;">&#40;</span>return_value<span style="color: #66cc66;">=</span><span style="color: #483d8b;">&quot;moooooooooock&quot;</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> mock.<span style="color: black;">mock</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #483d8b;">'moooooooooock'</span></pre></td></tr></table></div>

<p>Cela vous permet d&#8217;utiliser les objets mocks comme des remplacements pour des objets réels dans vos tests mais chiants à instancier comme une event loop, un serveur, une connexion à une base de données&#8230; Ca permet aussi de remplacer des appels très longs par des trucs instantanés.</p>
<p>Mais la partie vraiment fun, c&#8217;est qu&#8217;on peut associer des vrais objets avec des objets mocks :</p>

<div class="wp_syntax"><table><tr><td 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> VraiObjetSerieuxEtTout:
...     <span style="color: #ff7700;font-weight:bold;">def</span> faire_un_truc_super_serieux<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: #483d8b;">&quot;... and don't call me Shirley&quot;</span>
...     <span style="color: #ff7700;font-weight:bold;">def</span> faire_un_autre_truc_serieux<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: #483d8b;">&quot;why so serious ?&quot;</span>
...
<span style="color: #66cc66;">&gt;&gt;&gt;</span> sirius <span style="color: #66cc66;">=</span> VraiObjetSerieuxEtTout<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> sirius.<span style="color: black;">faire_un_truc_super_serieux</span> <span style="color: #66cc66;">=</span> MagicMock<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># It's a kinda magic, magic !</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> sirius.<span style="color: black;">faire_un_autre_truc_serieux</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #483d8b;">'why so serious ?'</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> sirius.<span style="color: black;">faire_un_truc_super_serieux</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'ieux'</span><span style="color: black;">&#41;</span>.<span style="color: black;">delamort</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">3</span>:<span style="color: #ff4500;">14</span><span style="color: black;">&#93;</span> + <span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">2</span><span style="color: black;">&#93;</span>
<span style="color: #66cc66;">&lt;</span>MagicMock name<span style="color: #66cc66;">=</span><span style="color: #483d8b;">'mock().delamort().__getitem__().__add__()'</span> <span style="color: #008000;">id</span><span style="color: #66cc66;">=</span><span style="color: #483d8b;">'140302103288296'</span><span style="color: #66cc66;">&gt;</span></pre></td></tr></table></div>

<p>Et là ça devient super sympa : vous pouvez utilisez vos vrais objets, et pour certains appels, juste vous faciliter la vie pour les tests.</p>
<h2>On dirait qu&#8217;on compte le nombre de balles que tu as tirées</h2>
<p>Puisque les objets mocks sont un peu les <a href="http://sametmax.com/merci-de-respecter-les-salopes">grosses salopes</a> de la programmation et acceptent tout ce qui vient (oups, je viens de tuer l’ambiance métaphore enfantine là), il peut être nécessaire de vérifier ce qui s&#8217;est passé. Or il se trouve qu&#8217;ils intègrent un historique des appels :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> sirius.<span style="color: black;">faire_un_truc_super_serieux</span>.<span style="color: black;">mock_calls</span>
<span style="color: black;">&#91;</span>call<span style="color: black;">&#40;</span><span style="color: #483d8b;">'ieux'</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span>
 call<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>.<span style="color: black;">delamort</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span>
 call<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>.<span style="color: black;">delamort</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>.<span style="color: #0000cd;">__getitem__</span><span style="color: black;">&#40;</span><span style="color: #008000;">slice</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">3</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">14</span><span style="color: #66cc66;">,</span> <span style="color: #008000;">None</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span>
 call<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>.<span style="color: black;">delamort</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>.<span style="color: #0000cd;">__getitem__</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>.<span style="color: #0000cd;">__add__</span><span style="color: black;">&#40;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">2</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span></pre></td></tr></table></div>

<p> Et comme vérifier qu&#8217;un appel a bien eu lieu est une tâche courante, <a href="https://docs.python.org/3/library/unittest.mock.html#unittest.mock.Mock.assert_called_with">des méthodes</a> pour les tests unitaires ont été intégrées :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> sirius.<span style="color: black;">faire_un_truc_super_serieux</span>.<span style="color: black;">assert_called_with</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'ieux'</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> sirius.<span style="color: black;">faire_un_truc_super_serieux</span>.<span style="color: black;">assert_called_with</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'not_ieux'</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;ipython-input-56-e8c4890f08d9&gt;&quot;</span><span style="color: #66cc66;">,</span> line <span style="color: #ff4500;">1</span><span style="color: #66cc66;">,</span> <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #66cc66;">&lt;</span>module<span style="color: #66cc66;">&gt;</span>
    sirius.<span style="color: black;">faire_un_truc_super_serieux</span>.<span style="color: black;">assert_called_with</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'not_ieux'</span><span style="color: black;">&#41;</span>
  File <span style="color: #483d8b;">&quot;/usr/lib/python3.4/unittest/mock.py&quot;</span><span style="color: #66cc66;">,</span> line <span style="color: #ff4500;">760</span><span style="color: #66cc66;">,</span> <span style="color: #ff7700;font-weight:bold;">in</span> assert_called_with
    <span style="color: #ff7700;font-weight:bold;">raise</span> <span style="color: #008000;">AssertionError</span><span style="color: black;">&#40;</span>_error_message<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;">from</span> cause
<span style="color: #008000;">AssertionError</span>: Expected call: mock<span style="color: black;">&#40;</span><span style="color: #483d8b;">'not_ieux'</span><span style="color: black;">&#41;</span>
Actual call: mock<span style="color: black;">&#40;</span><span style="color: #483d8b;">'ieux'</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<h2>On dirait que tu vas mettre ces porte-jartelles et&#8230;</h2>
<p>Pour finir, le module <code>mock</code> vient avec <code>patch()</code>, qui sert à, surprise, patcher les objets, et propose des <a href="http://sametmax.com/les-context-managers-et-le-mot-cle-with-en-python/">context managers</a> et des <a href="http://sametmax.com/comprendre-les-decorateurs-python-pas-a-pas-partie-1/">décorateurs</a> pour se faciliter la vie.</p>
<p>Par exemple, détourner <code>open()</code> temporairement :</p>

<div class="wp_syntax"><table><tr><td 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;">unittest</span>.<span style="color: black;">mock</span> <span style="color: #ff7700;font-weight:bold;">import</span> patch
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">with</span> patch<span style="color: black;">&#40;</span><span style="color: #483d8b;">'__main__.open'</span><span style="color: #66cc66;">,</span> mock_open<span style="color: black;">&#40;</span>read_data<span style="color: #66cc66;">=</span><span style="color: #483d8b;">'wololo'</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span> create<span style="color: #66cc66;">=</span><span style="color: #008000;">True</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">as</span> mock:
...     <span style="color: #ff7700;font-weight:bold;">with</span> <span style="color: #008000;">open</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'zefile'</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">as</span> h:
...         <span style="color: black;">result</span> <span style="color: #66cc66;">=</span> h.<span style="color: black;">read</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
...
<span style="color: #66cc66;">&gt;&gt;&gt;</span> mock.<span style="color: black;">assert_called_once_with</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'zefile'</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">assert</span> result <span style="color: #66cc66;">==</span> <span style="color: #483d8b;">'wololo'</span></pre></td></tr></table></div>

<p>Ou alors avoir une partie d&#8217;un module qui soit un mock pour tout un appel de fonction :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">@</span>patch<span style="color: black;">&#40;</span><span style="color: #483d8b;">'os.listdir'</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> ah<span style="color: black;">&#40;</span>mock<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">os</span>
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">os</span>.<span style="color: black;">listdir</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'.'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
    <span style="color: #808080; font-style: italic;"># l'objet mock initial est aussi passé en param automatiquement</span>
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>mock<span style="color: black;">&#41;</span>
ah<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #808080; font-style: italic;">## &lt;MagicMock name='listdir()' id='140302096346864'&gt;</span>
<span style="color: #808080; font-style: italic;">## &lt;MagicMock name='listdir' id='140302101454688'&gt;</span></pre></td></tr></table></div>

<p>Le module mock est vraiment très complet, avec des outils pour checker les signatures, passer <code>isinstance()</code>, overrider le contenu d&#8217;un dico, et tout un tas de cas particuliers et corner cases. Donc <a href="https://docs.python.org/3/library/unittest.mock.html#unittest.mock.patch">lisez la doc</a> si vous rencontrez un blocage avant de paniquer.</p>
<h2>Dis, comment on fait les bébés</h2>
<p>Exemple prit d&#8217;une base de code IRL, avec une fonction pytest qui teste un objet <code>response</code> représentant une réponse HTTP. Si on appelle <code>write()</code> sur cet objet sous-jacent elle doit faire des appels à deux méthodes privées et une méthode d&#8217;un objet Twisted.</p>
<p>Problème, ces méthodes :</p>
<ul>
<li>Supposent qu&#8217;une event loop est lancée.</li>
<li>Ecrivent sur le réseau.</li>
<li>Sont potentiellement appelées de manière asynchrone, en dehors de notre contrôle.</li>
<li>Ont des side effects donc on veut être certains qu&#8217;elles sont appelées, et avec les bons paramètres.</li>
</ul>
<p>Du coup, on les remplace par des objets mocks, et yala :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> test_write<span style="color: black;">&#40;</span>response<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">assert</span> response.<span style="color: black;">write</span> <span style="color: #66cc66;">!=</span> response._req.<span style="color: black;">write</span>
    response._disable_rendering <span style="color: #66cc66;">=</span> MagicMock<span style="color: black;">&#40;</span>name<span style="color: #66cc66;">=</span><span style="color: #483d8b;">'_disable_rendering'</span><span style="color: black;">&#41;</span>
    response._set_twisted_headers <span style="color: #66cc66;">=</span> MagicMock<span style="color: black;">&#40;</span>name<span style="color: #66cc66;">=</span><span style="color: #483d8b;">'_set_twisted_headers'</span><span style="color: black;">&#41;</span>
    response.<span style="color: black;">write</span><span style="color: black;">&#40;</span>b<span style="color: #483d8b;">'test'</span><span style="color: black;">&#41;</span>
    response._set_twisted_headers.<span style="color: black;">assert_called_once_with</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    response._disable_rendering.<span style="color: black;">assert_called_once_with</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">assert</span> response.<span style="color: black;">write</span> <span style="color: #66cc66;">==</span> response._req.<span style="color: black;">write</span>
    response._req.<span style="color: black;">write</span>.<span style="color: black;">assert_called_once_with</span><span style="color: black;">&#40;</span>b<span style="color: #483d8b;">'test'</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<h2>Et pourquoi ? Et pourquoi ? Et pourquoi ?</h2>
<p>Prochaines étapes, savoir quand tester, et quoi tester, mais aussi comment rendre un code plus testable. Probablement la partie qui sera la plus difficile à écrire pour moi, car c&#8217;est assez subjectif. On parlera sans doute du code coverage, et je gage que je vais devoir créer un petit projet bidon pour tester tout ça, du genre un minifieur d&#8217;URL ou autre. Faudra voir l&#8217;inspiration.</p>


feed_id: http://sametmax.com/?p=16319
title: Hasta la vista ! 4
uri: Hasta-la-vista-1
url: http://sametmax.com/hasta-la-vista/
content:
<p>Je me barre pour environ 2 semaines, et ne pondrai pas d&#8217;article pendant cette période.</p>
<p>Mettez ce temps à profit pour travailler votre lancer de nain.</p>


feed_id: http://sametmax.com/?p=16349
title: La branlette fait faire des économies 26
uri: La-branlette-fait-faire-des-économies-8-Recently-updated
url: http://sametmax.com/la-branlette-fait-faire-des-economies/
content:
<p>Vous connaissez cette sagesse populaire qui incite à ne jamais faire les courses le ventre vide ?</p>
<p>J&#8217;aimerais ajouter une règle d&#8217;hygiène de vie qu&#8217;il vaudrait enseigner dès le collège à tous les mâles en devenir : branlez-vous avant l&#8217;action.</p>
<p>Par action je n&#8217;entends pas la session de pirouette basque avec la voisine, bien que selon la situation ça puisse être une bonne stratégie.</p>
<p>Non, je parles de remplir un objectif qui demande un minimum de prise de décision suivi d&#8217;une action ou d&#8217;une interaction sociale majeure.</p>
<p>Dans Le Loup de Wall Street, qui n&#8217;est pas un monument du cinéma mais reste un divertissement scorcesien décent, un personnage secondaire résume bien le principe :</p>
<p><span class='embed-youtube' style='text-align:center; display: block;'><iframe class='youtube-player' type='text/html' width='1170' height='689' src='http://www.youtube.com/embed/aSn1g-6h1OQ?version=3&#038;rel=1&#038;fs=1&#038;showsearch=0&#038;showinfo=1&#038;iv_load_policy=1&#038;wmode=transparent' frameborder='0' allowfullscreen='true'></iframe></span></p>
<p>Et la raison est que, en plus de faire diminuer les tensions, se palucher un coup améliore sérieusement la capacité de choix, en retirant temporairement du diagramme décisionnel de votre tête tout un tas de losanges jaunes, biologiques et psychologiques.</p>
<p>Évidement, certains pourraient répliquer qu&#8217;il faudrait mieux avoir du self control, du recul et la capacité à gérer les situations en dehors de sa zone de confort.</p>
<p>A cela je répliquerais que oui, mais en attendant que chacun fasse murir le Clint Eastwood qui est en lui, un paquet de kleenex propose un bon rapport qualité/prix.</p>
<p>Avant un entretien de job, branlez-vous.</p>
<p>Avant de faire un gros achat, branlez-vous.</p>
<p>Avant d&#8217;aller dans une intense réunion, branlez-vous.</p>
<p>Avant de faire une code review, branlez-vous.</p>
<p>Avant de valider une mise en prod, branlez-vous.</p>
<p>Le seul cas où je ne recommande pas de se masturber, c&#8217;est pour la drague, contrairement à ce qu&#8217;on dit dans Marie à tout prix :</p>
<blockquote><p>You choke the chicken before any big date, don&#8217;t you? Tell me you spank the monkey before any big date. Oh my God, he doesn&#8217;t flog the dolphin before a big date. Are you crazy? That&#8217;s like going out there with a loaded gun! Of course that&#8217;s why you&#8217;re nervous. Oh my dear friend, please sit, please. Look, um, after you&#8217;ve had sex with a girl, and you&#8217;re lying in bed with her, are you nervous? No, you&#8217;re not, why? </p></blockquote>
<p>Parce que conserver une érection en suspens, ça garde motivé pour tendre vers son but, si je puis dire.</p>
<p>Pour le reste, dans le doute, branlez-vous.</p>
<p>Il en restera toujours quelque chose, n&#8217;est-pas ?</p>


feed_id: http://sametmax.com/?p=16360
title: Le don du mois 8
uri: Le-don-du-mois
url: http://sametmax.com/le-don-du-mois/
content:
<p>J&#8217;utilise Ubuntu au quotidien, et j&#8217;ai déjà donné au projet, mais les dernières décisions prises par l&#8217;équipe de la distrib ne me paraissent pas toujours judicieuses.</p>
<p>Aussi, afin de contribuer à Ubuntu, mais aussi à de nombreux autres projets, le don du mois sera pour le projet <a href="https://www.debian.org/">Debian</a>, qui est à la racine de nombreuses distribs, dont Ubuntu. Les bénéfices se feront donc en cascade.</p>
<p>L&#8217;équipe de Debian a su garder un cap en terme de qualité et de stabilité au cours des longues années de son existence, et sur un projet libre de cette taille, c&#8217;est un exploit. </p>
<p><a href="https://www.debian.org/donations.fr.html">$50 partent donc pour eux.</a> Avec <a href="http://linuxfr.org/users/elessar/journaux/debian-adopte-systemd-comme-init-par-defaut">l&#8217;adoption de systemd par défaut</a>, ils vont avoir besoin de ressources pour réaménager la caverne à trolls.</p>


feed_id: http://sametmax.com/?p=16365
title: Oh le beau scam ! 6
uri: Oh-le-beau-scam-4
url: http://sametmax.com/oh-le-beau-scam/
content:
<p>J&#8217;ai reçu ce mail ce matin :</p>
<blockquote><p>Attention: Important Notice , DOMAIN SERVICE NOTICE<br />
Domain Name: SITEDESAM.COM</p>
<p>Complete and return by fax to:<br />
1-206-278-9897</p>
<p>ATT: SAM<br />
ADMINISTRATIVE CONTACT<br />
&#8211;<br />
5686876587@CONTACT.GANDI.NET<br />
GANDI 63-65 BOULEVARD MASSENA &#8211; &#8211; (GANDI) PARIS &#8211; &#8211; &#8211; (GANDI) 75013<br />
(GANDI) FR<br />
WWW.SITEDESAM.COM<br />
Please ensure that your contact information is correct or make the necessary changes above </p>
<p>Requested Reply Before<br />
JUNE 08,2015</p>
<p>PART I: REVIEW SOLICITATION</p>
<p>Attn: SAM<br />
As a courtesy to domain name holders, we are sending you this notification for your business Domain name search engine registration. This letter is to inform you that it&#8217;s time to send in your registration and save.</p>
<p>Failure to complete your Domain name search engine registration by the expiration date may result in cancellation of this offer making it difficult for your customers to locate you on the web.</p>
<p>Privatization allows the consumer a choice when registering. Search engine subscription includes domain name search engine submission. You are under no obligation to pay the amounts stated below unless you accept this offer. Do not discard, this notice is not an invoice it is a courtesy reminder to register your domain name search engine listing so your customers can locate you on the web.</p>
<p>This Notice for: WWW.SITEDESAM.COM will expire on JUNE 08,2015 Act today!</p>
<p>Select Term: </p>
<p>[ ] 1 year   06/08/2015 &#8211; 06/08/2016 $75.00<br />
[ ] 2 year   06/08/2015 &#8211; 06/08/2017 $119.00<br />
[ ] 5 year   06/08/2015 &#8211; 06/08/2020 $199.05<br />
[ ] 10 year -Most Recommended- 06/08/2015 &#8211; 06/08/2025 $295.00<br />
[ ] Lifetime (NEW!) Limited time offer &#8211; Best value! Lifetime $499.00  </p>
<p>Today&#8217;s Date: _____________________ Signature: _____________________ </p>
<p>Payment by Credit Card<br />
Select the term above, then return by fax: 1-206-278-9897</p>
<p>SITEDESAM.COM</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-</p>
<p>By accepting this offer, you agree not to hold DS liable for any part. Note that THIS IS NOT A BILL. This is a solicitation. You are under no obligation to pay the amounts stated unless you accept this offer. The information in this letter contains confidential and/or legally privileged information from the notification processing department of the DS 3501 Jack Northrop Ave. Suite #F9238 Hawthorne, CA 90250 USA, This information is intended only for the use of the individual(s) named above. There is no pre-existing relationship between DS and the domain mentioned above. This notice is not in any part associated with a continuation of services for domain registration. Search engine submission is an optional service that you can use as a part of your website optimization and alone may not increase the traffic to your site. If you do not wish to receive further updates from DS reply with Remove to unsubscribe. If you are not the intended recipient, you are hereby notified that disclosur<br />
 e, copying, distribution or the taking of any action in reliance on the contents for this letter is strictly prohibited.</p></blockquote>
<p> Le mail est très bien fait, car en le scannant j&#8217;ai vu le nom de mon site, le mail de mon registrat, et le mot &#8220;expire&#8221; dedans en plus d&#8217;un formulaire à retourner par fax :). Le langage utilisé est particulièrement vicieux et bien composé, et il m&#8217;a donc forcé à le lire plus lentement pour bien comprendre qu&#8217;il s&#8217;agissait d&#8217;une grosse arnaque.</p>
<p> C&#8217;est comme ces lettres qu&#8217;on reçoit après la création d&#8217;une entreprise pour s&#8217;enregistrer auprès d&#8217;annuaires qui portent des noms qui font très sérieux comme &#8220;Enregistrement des membres des chambres commerciales&#8221;. </p>
<p> J&#8217;imagine bien le gars qui a 30000 problèmes à résoudre, la tête dans le guidon et qui fait sans chercher à comprendre. Ca doit rapporter une fortune;</p>


feed_id: http://sametmax.com/?p=16371
title: Templates de projet avec cookiecutter 8
uri: Templates-de-projet-avec-cookiecutter-2
url: http://sametmax.com/templates-de-projet-avec-cookiecutter/
content:
<p>Beaucoup de frameworks viennent avec des templates de projets maintenant. Django vient avec <code>django-admin startproject --template</code>, tandis que crossbar vient avec <code>crossbar init --template</code>. L&#8217;idée d&#8217;avoir de templates pour ses projets n&#8217;a rien de nouveau, d&#8217;ailleurs la plupart des OS modernes ont au moins ça intégré pour des fichiers. Ainsi Ubuntu à un dossière &#8220;Modèles&#8221;, et tout ce qu&#8217;il y a dedans peut être dupliqué ailleurs via un clic droit dans Nautilus.</p>
<p>Néanmoins la meilleure solution à ce jour vient de Audrey Roy, qui est avant tout connue pour avoir co-écrit le livre Two scoops of Django, et qui a aussi pondu <a href="http://cookiecutter.readthedocs.org/en/latest/readme.html">cookiecutter</a>.</p>
<p>L&#8217;outil est très simple. D&#8217;abord un <a href="http://sametmax.com/votre-python-aime-les-pip/">pip</a> pour l&#8217;installer :</p>
<p><code>pip install cookiecutter</code></p>
<p>Notez que bien que le projet soit en Python, les templates peuvent être en n&#8217;importe quel langage, cookiecutter s&#8217;en branle. Lui, il va juste copier le contenu du template dans un dossier, et remplacer les variables notées <code>{{}}</code> dedans.</p>
<p>Pour commencer, on créé un dossier nommé <code>{{cookiecutter.repo_name}}</code> qui va contenir le template de son projet. Oui, le nom du dossier est <code>{{cookiecutter.repo_name}}</code>. En effet les noms de dossiers et fichiers sont aussi templatisables, et passés à la moulinette de <a href="https://en.wikipedia.org/wiki/Jinja_%28template_engine%29">jinja2</a>.</p>
<p>Dans ce dossier, on peut mettre tous les fichiers qu&#8217;on veut, avec des noms normaux, ou avec des variables. Le contenu des fichiers peut, bien entendu, contenir aussi des variables. Les variables sont toujours de la forme <code>{{cookiecutter.nom_de_variable}}</code>.</p>
<p>Ensuite, à côté de notre dossier nommé <code>{{cookiecutter.repo_name}}</code> (le dossier du template), on peut créer un fichier <code>cookiecutter.json</code> qui va contenir les valeurs par défaut de nos variables :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #009900;">&#123;</span>
    <span style="color: #3366CC;">&quot;repo_name&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;nouveau_projet&quot;</span><span style="color: #339933;">,</span>
    <span style="color: #3366CC;">&quot;version&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;0.1.0&quot;</span><span style="color: #339933;">,</span>
    <span style="color: #3366CC;">&quot;autre_variable&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;Bidule&quot;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>Enfin pour récolter les fruits de son labeur, on lance <code>cookiecutter /chemin/vers/template</code> et l&#8217;outil va vous poser tout un tas de question pour remplir les variables, puis va générer le nouveau projet dans le dossier courant.</p>
<p>Cookiecutter accepte aussi des urls de repo git et mercurial comme source de template, et l&#8217;auteur de l&#8217;outil fournit un <a href="https://github.com/audreyr/cookiecutter-pypackage">template de projet Python</a> très complet par ce biais. </p>
<p>On va l&#8217;utiliser comme exemple.</p>
<p>Voici son contenu :</p>
<pre>├── cookiecutter.json <= valeur par défaut des variables
├── {{cookiecutter.repo_name}} <= template du projet
│   ├── AUTHORS.rst
│   ├── CONTRIBUTING.rst
│   ├── {{cookiecutter.repo_name}}
│   │   ├── {{cookiecutter.repo_name}}.py
│   │   └── __init__.py
│   ├── docs
│   │   ├── authors.rst
│   │   ├── conf.py
│   │   ├── contributing.rst
│   │   ├── history.rst
│   │   ├── index.rst
│   │   ├── installation.rst
│   │   ├── make.bat
│   │   ├── Makefile
│   │   ├── readme.rst
│   │   └── usage.rst
│   ├── HISTORY.rst
│   ├── LICENSE
│   ├── Makefile
│   ├── MANIFEST.in
│   ├── README.rst
│   ├── requirements.txt
│   ├── setup.cfg
│   ├── setup.py
│   ├── tests
│   │   ├── __init__.py
│   │   └── test_{{cookiecutter.repo_name}}.py
│   └── tox.ini
└── README.rst</pre>
<p>Certains usages de variables sont assez évident, comme par exemple le fichier __init__:</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># -*- coding: utf-8 -*-</span>
&nbsp;
__author__ <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">'{{ cookiecutter.full_name }}'</span>
__email__ <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">'{{ cookiecutter.email }}'</span>
__version__ <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">'{{ cookiecutter.version }}'</span></pre></td></tr></table></div>

<p>D'autres sont assez malines et inattendues comme le fichier de test :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;">#!/usr/bin/env python</span>
<span style="color: #808080; font-style: italic;"># -*- coding: utf-8 -*-</span>
&nbsp;
<span style="color: #483d8b;">&quot;&quot;&quot;
test_{{ cookiecutter.repo_name }}
----------------------------------
Tests for `{{ cookiecutter.repo_name }}` module.
&quot;&quot;&quot;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">unittest</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">from</span> <span style="color: black;">&#123;</span><span style="color: black;">&#123;</span> cookiecutter.<span style="color: black;">repo_name</span> <span style="color: black;">&#125;</span><span style="color: black;">&#125;</span> <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: black;">&#123;</span><span style="color: black;">&#123;</span> cookiecutter.<span style="color: black;">repo_name</span> <span style="color: black;">&#125;</span><span style="color: black;">&#125;</span>
&nbsp;
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> Test<span style="color: black;">&#123;</span><span style="color: black;">&#123;</span> cookiecutter.<span style="color: black;">repo_name</span>|capitalize <span style="color: black;">&#125;</span><span style="color: black;">&#125;</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">unittest</span>.<span style="color: black;">TestCase</span><span style="color: black;">&#41;</span>:
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> setUp<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;">pass</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> test_something<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;">pass</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> tearDown<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;">pass</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">if</span> __name__ <span style="color: #66cc66;">==</span> <span style="color: #483d8b;">'__main__'</span>:
    <span style="color: #dc143c;">unittest</span>.<span style="color: black;">main</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>On note l'usage du filtre jinja <code>capitalize</code>. Tous les outils de jinja sont à disposition, ce serait con de s'en priver.</p>
<p>Pour utiliser le template on fait <code>$ cookiecutter https://github.com/audreyr/cookiecutter-pypackage.git</code>, ce qui nous donne :</p>
<pre>
Clonage dans 'cookiecutter-pypackage'...
remote: Counting objects: 505, done.
remote: Total 505 (delta 0), reused 0 (delta 0), pack-reused 505
Réception d'objets: 100% (505/505), 77.89 KiB | 0 bytes/s, done.
Résolution des deltas: 100% (265/265), done.
Vérification de la connectivité... fait.
full_name (default is "Audrey Roy")? Sam
email (default is "audreyr@gmail.com")? lesametlemax@gmail.com
github_username (default is "audreyr")? sam
project_name (default is "Python Boilerplate")? essai
repo_name (default is "boilerplate")? essai
project_short_description (default is "Python Boilerplate contains all the boilerplate you need to create a Python package.")? C'est un essai j'ai dis
release_date (default is "2015-01-11")? 
year (default is "2015")? 
version (default is "0.1.0")? </pre>
<p>Notez les valeurs par défaut du fichier JSON, qui sont celles de l'auteur.</p>
<p>Le résultat généré :</p>
<pre>
├── essai
│   ├── AUTHORS.rst
│   ├── CONTRIBUTING.rst
│   ├── docs
│   │   ├── authors.rst
│   │   ├── conf.py
│   │   ├── contributing.rst
│   │   ├── history.rst
│   │   ├── index.rst
│   │   ├── installation.rst
│   │   ├── make.bat
│   │   ├── Makefile
│   │   ├── readme.rst
│   │   └── usage.rst
│   ├── essai
│   │   ├── essai.py
│   │   └── __init__.py
│   ├── HISTORY.rst
│   ├── LICENSE
│   ├── Makefile
│   ├── MANIFEST.in
│   ├── README.rst
│   ├── requirements.txt
│   ├── setup.cfg
│   ├── setup.py
│   ├── tests
│   │   ├── __init__.py
│   │   └── test_essai.py
│   └── tox.ini
└── README.rst</pre>
<p>Le fichier __init__ est devenu :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># -*- coding: utf-8 -*-</span>
&nbsp;
__author__ <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">'Sam'</span>
__email__ <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">'lesametlemax@gmail.com'</span>
__version__ <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">'0.1.0'</span></pre></td></tr></table></div>

<p>Et le fichier de test :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;">#!/usr/bin/env python</span>
<span style="color: #808080; font-style: italic;"># -*- coding: utf-8 -*-</span>
&nbsp;
<span style="color: #483d8b;">&quot;&quot;&quot;
test_essai
----------------------------------
&nbsp;
Tests for `essai` module.
&quot;&quot;&quot;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">unittest</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">from</span> essai <span style="color: #ff7700;font-weight:bold;">import</span> essai
&nbsp;
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> TestEssai<span style="color: black;">&#40;</span><span style="color: #dc143c;">unittest</span>.<span style="color: black;">TestCase</span><span style="color: black;">&#41;</span>:
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> setUp<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;">pass</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> test_something<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;">pass</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> tearDown<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;">pass</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">if</span> __name__ <span style="color: #66cc66;">==</span> <span style="color: #483d8b;">'__main__'</span>:
    <span style="color: #dc143c;">unittest</span>.<span style="color: black;">main</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>L'outil accepte <a href="http://cookiecutter.readthedocs.org/en/latest/advanced_usage.html">un beau degré de customisation</a>, avec un fichier de configuration général au niveau de l'utilisateur (et donc des valeurs par défaut par utilisateur), une API programmable en Python, des hooks pre et post generation (qui permettent d'injecter des variables dynamiquement comme par exemple un uuid ou un timestamp).</p>
<p>Donc si vous recréez souvent les mêmes layout de projet encore et encore, pensez à cookiecutter.</p>
<p>Mais surtout, surtout, si vous codez votre propre framework, ne faites pas comme Django, utilisez l'API de cookiecutter au lieu de réinventer la roue.</p>


