# articles

feed_id: http://sametmax.com/?p=13066
title: Debugger Python à distance avec rpdb 7
uri: Debugger-Python-à-distance-avec-rpdb-2
url: http://sametmax.com/debugger-python-a-distance-avec-rpdb/
content:
<p>Vous aimez <a href="http://sametmax.com/debugger-en-python-les-bases-de-pdb/">pdb</a> parce que c&#8217;est cool. Et vous adorez <a href="https://pypi.python.org/pypi/pdbpp/">pdbpp</a> parce que c&#8217;est trop cool.</p>
<p>Mais parfois vous n&#8217;avez pas accès à une console sur votre process : il est derrière un nginx, ou même sur une machine distante.</p>
<p><a href="https://pypi.python.org/pypi/rpdb/">rpdb</a> vient résoudre ce problème en lançant un serveur telnet qui donne accès à votre debugger.</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> rpdb</pre></td></tr></table></div>

<p>Puis :</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> rpdb<span style="color: #66cc66;">;</span> rpdb.<span style="color: black;">set_trace</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Et après vous prenez votre client telnet favoris, et vous accédez à votre débugger :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="bash" style="font-family:monospace;">telnet 127.0.0.1 <span style="color: #000000;">4444</span></pre></td></tr></table></div>

<p>Bien entendu, si vous êtes à distance, remplacez 127.0.0.1 par l&#8217;ip de la machine. Le port est configurable également :</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> rpdb
debugger <span style="color: #66cc66;">=</span> rpdb.<span style="color: black;">Rpdb</span><span style="color: black;">&#40;</span>port<span style="color: #66cc66;">=</span><span style="color: #ff4500;">12345</span><span style="color: black;">&#41;</span>
debugger.<span style="color: black;">set_trace</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Et derrière, ça lance <code>pdb</code>, donc <code>pdbpp</code> est lancé automatiquement si il est installé. Joie.</p>


feed_id: http://sametmax.com/?p=15699
title: Gérer plusieurs versions de Python avec “py” sous Windows 7
uri: Gérer-plusieurs-versions-de-Python-avec-py-sous-Windows-6
url: http://sametmax.com/gerer-plusieurs-versions-de-python-avec-py-sous-windows/
content:
<p>Il est courant de vouloir installer plusieurs versions de Python. Pour faire des tests, pour s&#8217;assurer que son code est portable, pour utiliser des libs qui marchent uniquement sur une des versions, etc.</p>
<p>Sous Linux, c&#8217;est facile : chaque interpretteur est préfixé. Par exemple, sous Ubuntu, si je veux utiliser Python 3.4, je l&#8217;installe :</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> python3.4</pre></td></tr></table></div>

<p>Et si je lance <code>python</code>, ça me lance la 2.7 car c&#8217;est celle de base. Mais si je lance <code>python3.4</code>, ça me lance bien la 3.4. </p>
<p>Au final, on finit par utiliser des <a href="virtuels">environnements virtuels</a> qui isolent des versions de Python particulières. Mais ça ne retire pas l&#8217;envie de pouvoir choisir sa version de Python au niveau du système, ce qui reste difficile à faire sous Windows.</p>
<p>Or, depuis la version 3.3, l&#8217;installeur pour cet OS de Python installe la commande <a href="https://docs.python.org/3/using/windows.html#launcher">py</a>, qui permet de choisir quelle version de Python on lance.</p>
<h2>Dans un terminal</h2>
<p>Si dans une console vous faites :</p>

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

<p>Il lancera le shell de votre installation Python 2.x la plus récente.</p>
<p>Si vous faites :</p>

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

<p>Il exécutera le script avec votre installation Python 2.x la plus récente.</p>
<p>Mais vous pouvez passez un flag <code>-version</code> pour forcer une version de Python. Lancer le shell Python avec la 3.3 :</p>

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

<p>Lancer un script avec la 3.4 :</p>

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

<p>Cela suppose que vous avez la 3.3 et la 3.4, installés, évidement.</p>
<p>La syntaxe est surprenante. J&#8217;aurais pensé qu&#8217;ils mettraient un truc du genre <code>py -i 3.4</code> mais non, c&#8217;est direct <code>-numero</code>.</p>
<p>La commande <code>py</code> accepte aussi les paramètres qu&#8217;on passerait normalement à la commande <code>python</code>, et notament l&#8217;option <code>-m module</code>, qui permet de lancer un module en particulier. </p>
<p>C&#8217;est pratique pour lancer <code>ipython</code> ou <code>pip</code> avec une version particulière. Par exemple pour installer <a href="https://github.com/tavendo/AutobahnPython/">autobahn</a> uniquement pour la version 3.4 et donc utiliser <code>asyncio</code> :</p>

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

<h2>Bang !</h2>
<p>La commande <code>py</code> reconnait également la ligne <em>shebang</em>, cette syntaxe unix qui dit quel interpretteur utiliser. Si vous mettez sur la première ligne de votre script :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;">#! python3.4</span></pre></td></tr></table></div>

<p>Alors :</p>

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

<p>Invoquera python 3.4.</p>
<p>La commande est capable de se débrouiller avec les chemins Unix, afin de garder la portabilité. Donc si vous faites :</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 python2.7</span></pre></td></tr></table></div>

<p>Alors :</p>

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

<p>Va ignorer le debut de la ligne, et prendre l&#8217;installation locale de Python 2.7 pour lancer le script.</p>
<h2>On click</h2>
<p>Si vous installez la version Python 3.3 ou 3.4 en premier, les fichiers <code>.py</code> seront associés à la commande <code>py</code>. Donc si vous cliquez sur un script Python avec une ligne shebang, la bonne version sera lancée.</p>
<p>Mais si vous avez installé Python 2.x avant, il est possible que vos fichiers <code>.py</code> soient encore associés directement à la commande <code>python</code> ordinnaire.</p>
<p>Pour changer cela, faites un clic droit sur un fichier <code>.py</code>, modifiez le programme qui ouvre ce fichier et faites le pointer sur <code>"C:\Windows\py.exe"</code>.</p>


feed_id: http://sametmax.com/?p=15712
title: Qu’est-ce que le duck typing et à quoi ça sert ? 5
uri: Qu-est-ce-que-le-duck-typing-et-à-quoi-ça-sert-2
url: http://sametmax.com/quest-ce-que-le-duck-typing-et-a-quoi-ca-sert/
content:
<p>Le duck typing, qu&#8217;on pourrait traduire par &#8220;typage canard&#8221; mais on ne le fera pas parce que c&#8217;est très moche, est une manière de créer des <a href="http://sametmax.com/quest-ce-quune-api/">APIs</a> basée sur la philosophie que l&#8217;aspect pratique est plus important que la pureté du code.</p>
<p>L&#8217;idée est de créer des signatures de <a href="http://sametmax.com/les-trucmuchables-en-python/">callable</a> qui acceptent des paramètres en fonction de leur comportement, pas leur type :</p>
<blockquote><p>Si ça marche comme un canard et que ça fait le bruit d&#8217;un canard, alors ça ressemble assez à un canard pour le traiter comme un canard</p></blockquote>
<p>Imaginez que vous ayez un objet avec un interface ICanard:</p>
<pre>
class ICanar:
    def coin():
        pass
</pre>
<p>Une fonction qui est programmée selon le duck typing acceptera comme argument un objet qui possède la méthode <code>coin</code>, peut importe si il implémente cette interface ou non.</p>
<p>En gros, si un paramètre possède une interface suffisante pour nous, ou peut être casté en un objet avec une interface suffisante pour nous, on l&#8217;accepte. Cela rend un callable plus générique.</p>
<p>Ok, trève de bavardage, qu&#8217;est-ce que ça implique, dans la vraie vie vivante ?</p>
<p>Si je fais une fonction qui retourne le premier élément d&#8217;une liste ou un élément par défaut :</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> getfirst<span style="color: black;">&#40;</span>lst<span style="color: #66cc66;">,</span> default<span style="color: #66cc66;">=</span><span style="color: #008000;">None</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">try</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> lst<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span>
    <span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">IndexError</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> default</pre></td></tr></table></div>

<p>Pratique, et ça marche sur d&#8217;autres itérables :</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> getfirst<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: #66cc66;">,</span> <span style="color: #ff4500;">3</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
<span style="color: #ff4500;">1</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> getfirst<span style="color: black;">&#40;</span><span style="color: #483d8b;">'abcde'</span><span style="color: black;">&#41;</span>
<span style="color: #483d8b;">'a'</span></pre></td></tr></table></div>

<p>On a une forme de duck typing : si on peut récupérer le premier élément, alors ça suffit pour nous. Peut importe qu&#8217;il s&#8217;agit d&#8217;une liste ou d&#8217;un tuple.</p>
<p>On peut néanmoins améliorer la généricité de cette fonction:</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> getfirst<span style="color: black;">&#40;</span>iterable<span style="color: #66cc66;">,</span> default<span style="color: #66cc66;">=</span><span style="color: #008000;">None</span><span style="color: black;">&#41;</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;">return</span> x
    <span style="color: #ff7700;font-weight:bold;">return</span> default</pre></td></tr></table></div>

<p>Ici, le comportement recherché est qu&#8217;on puisse faire une une boucle <code>for</code> dessus, pas qu&#8217;on puisse récupérer un élément par son index.</p>
<p>Cela rend la fonction encore plus flexible, ainsi elle marche sur les générateurs, les flux, les fichiers:</p>
<pre lang"python>>>> getfirst(open('/etc/fstab'))
'# /etc/fstab: static file system information.\n'</pre>
<p>Un autre exemple ? La fonction Python <code>sum</code> par exemple, accepte tout types de nombres :</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;">sum</span><span style="color: black;">&#40;</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: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># integers</span>
<span style="color: #ff4500;">6</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #008000;">sum</span><span style="color: black;">&#40;</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">1.3</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">2.4</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">3.5</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># floats</span>
<span style="color: #ff4500;">7.2</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #008000;">sum</span><span style="color: black;">&#40;</span><span style="color: black;">&#40;</span>1j<span style="color: #66cc66;">,</span> 2j<span style="color: #66cc66;">,</span> 3j<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># complexes</span>
6j</pre></td></tr></table></div>

<p>Sympas, mais l&#8217;addition en Python supporte bien plus que les nombres :</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: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span> + <span style="color: black;">&#91;</span><span style="color: #ff4500;">2</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;">&gt;&gt;&gt;</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: black;">&#41;</span> + <span style="color: black;">&#40;</span><span style="color: #ff4500;">2</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">4</span><span style="color: black;">&#41;</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;">2</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">4</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #483d8b;">&quot;a&quot;</span> + <span style="color: #483d8b;">&quot;b&quot;</span>
<span style="color: #483d8b;">'ab'</span></pre></td></tr></table></div>

<p>Mais <code>sum</code> ne les accepte 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> <span style="color: #008000;">sum</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;a&quot;</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">&quot;b&quot;</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-24-1e5baeda1183&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;">sum</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;a&quot;</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">&quot;b&quot;</span><span style="color: black;">&#41;</span>
<span style="color: #008000;">TypeError</span>: <span style="color: #008000;">sum</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> can<span style="color: #483d8b;">'t sum strings [use '</span><span style="color: #483d8b;">'.join(seq) instead]</span></pre></td></tr></table></div>

<p>Il est possible de faire un <code>sum</code> plus générique :</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> sumum<span style="color: black;">&#40;</span>*iterable<span style="color: #66cc66;">,</span> start<span style="color: #66cc66;">=</span><span style="color: #008000;">None</span><span style="color: #66cc66;">,</span> default<span style="color: #66cc66;">=</span><span style="color: #008000;">None</span><span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;"># On donne à l'utilisateur la possibilité</span>
    <span style="color: #808080; font-style: italic;"># de passer un premier élément</span>
    <span style="color: #ff7700;font-weight:bold;">if</span> start <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #008000;">None</span>:
        <span style="color: #808080; font-style: italic;"># on récupère le premier élément</span>
        <span style="color: #ff7700;font-weight:bold;">try</span>:
            start<span style="color: #66cc66;">,</span> *iterable <span style="color: #66cc66;">=</span> iterable
        <span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">ValueError</span>:
            <span style="color: #808080; font-style: italic;"># Il n'y a aucun élément dans l'itérable</span>
            <span style="color: #808080; font-style: italic;"># donc on retourne la valeur par default</span>
            <span style="color: #ff7700;font-weight:bold;">return</span> default
    <span style="color: #808080; font-style: italic;"># on additionne</span>
    <span style="color: #ff7700;font-weight:bold;">for</span> x <span style="color: #ff7700;font-weight:bold;">in</span> iterable:
        start +<span style="color: #66cc66;">=</span> x
    <span style="color: #ff7700;font-weight:bold;">return</span> start</pre></td></tr></table></div>

<p>Le duck typing, à son maximum :</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> sumum<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: #483d8b;">'abc'</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> sumum<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: #66cc66;">,</span> <span style="color: black;">&#91;</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: black;">&#41;</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></pre></td></tr></table></div>

<p>Le duck typing implique aussi une prise de décision. Qu&#8217;est-ce qui serait le plus pratique ? De pouvoir additionner tous les types additionnables ? Ou de pouvoir additionner n&#8217;importe quoi qui ressemble à un nombre ?</p>
<p>Imaginons que la plupart de nos libs, plutôt que de fournir la possibilité d&#8217;additionner, propose la possibilité de caster vers un <code>float</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;">class</span> Temperature:
    <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> value<span style="color: #66cc66;">,</span> unit<span style="color: #66cc66;">=</span><span style="color: #483d8b;">'C'</span><span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>.<span style="color: black;">value</span> <span style="color: #66cc66;">=</span> <span style="color: #008000;">float</span><span style="color: black;">&#40;</span>value<span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">unit</span> <span style="color: #66cc66;">=</span> unit
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__float__</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;">if</span> <span style="color: #008000;">self</span>.<span style="color: black;">unit</span> <span style="color: #66cc66;">==</span> <span style="color: #483d8b;">'C'</span>:
            <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>.<span style="color: black;">value</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">self</span>.<span style="color: black;">unit</span> <span style="color: #66cc66;">==</span> <span style="color: #483d8b;">'K'</span>:
            <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>.<span style="color: black;">value</span> - <span style="color: #ff4500;">273.15</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">self</span>.<span style="color: black;">unit</span> <span style="color: #66cc66;">==</span> <span style="color: #483d8b;">'F'</span>:
            <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">value</span> - <span style="color: #ff4500;">32</span><span style="color: black;">&#41;</span> * <span style="color: #ff4500;">5</span>/<span style="color: #ff4500;">9</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__repr__</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: #483d8b;">'%s %s'</span> % <span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">value</span><span style="color: #66cc66;">,</span> <span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">unit</span> <span style="color: #66cc66;">!=</span> <span style="color: #483d8b;">'K'</span><span style="color: black;">&#41;</span>*<span style="color: #483d8b;">'°'</span>+<span style="color: #008000;">self</span>.<span style="color: black;">unit</span><span style="color: black;">&#41;</span>
&nbsp;
t1 <span style="color: #66cc66;">=</span> Temperature<span style="color: black;">&#40;</span><span style="color: #ff4500;">5</span><span style="color: black;">&#41;</span>
t2 <span style="color: #66cc66;">=</span> Temperature<span style="color: black;">&#40;</span><span style="color: #ff4500;">3</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'K'</span><span style="color: black;">&#41;</span>
t3 <span style="color: #66cc66;">=</span> Temperature<span style="color: black;">&#40;</span><span style="color: #ff4500;">30</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'F'</span><span style="color: black;">&#41;</span>
t1<span style="color: #66cc66;">,</span> t2<span style="color: #66cc66;">,</span> t3
<span style="color: #808080; font-style: italic;">## (5.0 °C, 3.0 K, 30.0 °F)</span></pre></td></tr></table></div>

<p>Dans ce cas notre fonction pourrait convertir tous les éléments d&#8217;un itérable avant addition :</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> sumcast<span style="color: black;">&#40;</span>*iterable<span style="color: #66cc66;">,</span> start<span style="color: #66cc66;">=</span><span style="color: #008000;">None</span><span style="color: #66cc66;">,</span> default<span style="color: #66cc66;">=</span><span style="color: #008000;">None</span><span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;"># On donne à l'utilisateur la possibilité</span>
    <span style="color: #808080; font-style: italic;"># de passer un premier élément</span>
    <span style="color: #ff7700;font-weight:bold;">if</span> start <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #008000;">None</span>:
        <span style="color: #808080; font-style: italic;"># on récupère le premier élément</span>
        <span style="color: #ff7700;font-weight:bold;">try</span>:
            start<span style="color: #66cc66;">,</span> *iterable <span style="color: #66cc66;">=</span> iterable
        <span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">ValueError</span>:
            <span style="color: #808080; font-style: italic;"># Il n'y a aucun élément dans l'itérable</span>
            <span style="color: #808080; font-style: italic;"># donc on retourne la valeur par default</span>
            <span style="color: #ff7700;font-weight:bold;">return</span> default
    <span style="color: #808080; font-style: italic;"># on additionne en convertissant tout en float</span>
    start <span style="color: #66cc66;">=</span> <span style="color: #008000;">float</span><span style="color: black;">&#40;</span>start<span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">for</span> x <span style="color: #ff7700;font-weight:bold;">in</span> iterable:
        start +<span style="color: #66cc66;">=</span> <span style="color: #008000;">float</span><span style="color: black;">&#40;</span>x<span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> start
&nbsp;
<span style="color: #66cc66;">&gt;&gt;&gt;</span> sumcast<span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">&quot;3&quot;</span><span style="color: #66cc66;">,</span> t1<span style="color: #66cc66;">,</span> t2<span style="color: #66cc66;">,</span> t3<span style="color: black;">&#41;</span>
-<span style="color: #ff4500;">262.26111111111106</span></pre></td></tr></table></div>

<p>Dans tous les cas, on se fiche complètement que nos objets soient d&#8217;un type précis ou qu&#8217;ils implémentent une interface précise à partir du moment où leur API est suffisamment proche du ce type ou de l&#8217;interface dont on a besoin.  </p>
<p>Le duck typing a beau être une pratique vouée à simplifier la vie au prix du formalisme, il ne dispense pas de documenter votre code à propos de cette subtilité afin que l&#8217;utilisateur final n&#8217;ait pas de mauvaise surprise.</p>
<p>Il convient de ne pas abuser du duck typing, qui est là pour rendre service uniquement. Si vous ajoutez des cas farfelus dans votre code pour supporter des situations rares, vous le rendez plus compliqué et moins robuste. Visez la généricité pour les situations les plus courantes, pas toutes les situations possibles.</p>
<p>Et souvenez-vous que plus on est dynamique sur les types, plus on perd en performance. Il faut savoir quelle part de compromis on est prêt à faire.</p>


feed_id: http://sametmax.com/?p=11795
title: Hypnose & Domination 9
uri: Hypnose-Domination-4-Recently-updated
url: http://sametmax.com/hypnose-domination/
content:
<p style="text-align: center;"><em><small>Ceci est un post invité de <a href="http://sametmax.com/author/Bussiere/">Bussiere</a> posté sous licence <a href="http://creativecommons.org/licenses/by/3.0/">creative common 3.0 unported</a>.</small></em></p>
<p>Ce petit article a pour but d&#8217;expliquer selon moi ce qu&#8217;est l&#8217;hypnose et comment cela agit pour moi comme un exhausteur de gout pour la domination / sexe.</p>
<p>L&#8217;hypnose de mon point de vue est un hack du cerveau, il revient a faire tilter le cerveau de quelqu&#8217;un pour en prendre le contrôle.</p>
<p>Selon moi 95% des gens sont sensibles a l&#8217;hypnose et 15% de ses 95 % sont ultras sensibles.<br />
Les spectacles que vous verrez ne sont que sur les gens ultra sensibles, après la prise de drogue, le manque de sommeil et l&#8217;alcool peuvent rendre les gens ultra sensibles. De plus une personne qui perd ses repères devient plus sensible a l&#8217;hypnose j&#8217;ai déjà eu l&#8217;occasion de tester hypnose et <a href="http://www.urbex.me/">urbex</a> par exemple dans le cadre de la domination.</p>
<p>La domination et le <a href="http://fr.wikipedia.org/wiki/Extase_masochiste" title="subspace">sub space</a> pour moi se rapprochent énormément de l&#8217;hypnose, pour moi les deux étaient fait pour se Rencontrer.</p>
<p>De base la <a href="https://fetlife.com">domination</a> rend quelqu&#8217;un de sensible ultra sensible, et quelqu&#8217;un ayant jouis et du coup abaissant toute ses défense devient ultra sensible a l&#8217;hypnose de même que quelqu&#8217;un en subspace.</p>
<p><img src="media/c1cd0d39.5027310004e8cf9557396b4ba55c10284a7dec720.jpg" data-original-source="http://img11.hostingpics.net/pics/5027310004e8cf9557396b4ba55c10284a7dec720.jpg" alt="Exemple" /></p>
<p>J&#8217;utilise l&#8217;hypnose en domination de plusieurs manières :</p>
<p>Soit pour laisser des mots de commande exemples :</p>
<p>Miaouss pour que la soumise ne puisse que miauler et ne plus parler.<br />
Persian pour qu&#8217;elle puisse reparler de nouveau<br />
Spectre pour qu&#8217;elle se mette a genoux et ne puisse plus bouger.<br />
Piroli pour qu&#8217;elle se fasse plaisir seule.<br />
Rondoudou pour qu&#8217;elle s&#8217;endorme et parte.<br />
Dracofeu pour la montée de chaleur.</p>
<p>Le plus amusant étant de pouvoir jouer avec des mots de commande en public&#8230;</p>
<p>Soit par association :</p>
<p>J&#8217;associe les cordes au plaisir </p>
<p><img src="media/fc95913d.4552350004ee5d0415a5bfba9fc1051c11d1c6720.jpg" data-original-source="http://img4.hostingpics.net/pics/4552350004ee5d0415a5bfba9fc1051c11d1c6720.jpg" alt="Voila ce que je fais et un mec pour changer un peu" /></p>
<p>et quand j&#8217;attache quelqu&#8217;un, cette personne ressent des montées de chaleur plus les cordes la touche. Chose que je fais souvent en performance.</p>
<p>J&#8217;ai remarqué que les cordes augmentaient les effets de l hypnose au point ou j&#8217;ai des amies qui me demande de les attacher habillées et de les hypnotiser pour les détendre après.</p>
<p>Une chose amusante est aussi de lier un foulard au plaisir et de passer le foulard sur le corps.</p>
<p>Mais sans aller jusqu’à l&#8217;hypnose &#8220;dure&#8221; le conditionnement fait partie de l&#8221;hypnose et tout le monde peut le faire. Prenez du velours, si dans les préliminaire quand votre partenaire éprouve du plaisir vous jouez avec un morceau de velours régulièrement, ce morceau de velours sera associé au plaisir. Donc il y aura un effet d&#8217;association qui décuplera le reste, et parfois selon votre partenaire juste sortir ce morceau de tissus suffira a le / la faire rougir.</p>
<p>Soit pour augmenter la sensibilité au reste :<br />
Il suffit par hypnose de conditionner la personne et de lui augmenter tout les sens pour qu&#8217;elle ressente encore plus de choses.</p>
<p>Apres l&#8217;hypnose fait peur j&#8217;ai des personnes qui acceptent de me laisser leur corps, je peux les attacher nues mais pas toucher a leur esprit. C&#8217;est leur choix et je le respecte mais j&#8217;ai du mal a comprendre dans la mesure ou le corps pour moi est une porte sur l&#8217;esprit.</p>
<p>J&#8217;aimerai savoir si d&#8217;autres personnes pratiquent aussi l&#8217;hypnose avec la domination ici.</p>
<p>Et en tant que dominateur j’apprécie particulièrement le contrôle sur l&#8217;esprit qui pour moi est largement au dessus du corps surtout chez les femmes. Les femmes étant largement plus mental que les hommes, arriver a jouer avec leur esprit est une satisfaction largement plus gratifiante que juste jouer avec les corps.</p>
<p>Sérieusement si vous arrivez a tenir une femme par le mental vous l&#8217;emmenez ou vous voulez &#8230;<br />
Tout ce qui est préliminaires , jeux , situations , rôles contribue a conditionner une femme et a lui donner plus de plaisir. Sans aller jusqu’à l’hypnose je recommande d’être joueur.</p>
<p>L&#8217;hypnose est un outil très intéressant pour tout ce qui touche a la domination si on le rajoute au reste, il en multiplie les effets et le reste décuple les effets de l&#8217;hypnose.</p>
<p>Quand vous forcez quelqu&#8217;un a se mettre a genoux devant vous , ou qu&#8217;il est vulnérable face a vous l&#8217;hypnose marchera mieux. Quand vous faites oublier son nom a quelqu&#8217;un en &#8220;jouant&#8221; avec lui il devient plus sensible a l&#8217;hypnose.</p>
<p>Bon par contre il y a des questions d’éthiques , personnellement j&#8217;ai l’éthique du bdsm qui consiste en un safe word, d’être sur du consentement de la personne sans aucun biais (hypnose, alcool , drogue , fatigue) et souvent de définir un contrat avec la personne sur les choses permises. Et en cas d&#8217;absence de contrat je m’abstiens de toute choses plus poussées et j&#8217;y vais par pallier.</p>
<p>Ma plus belle réussite reste d&#8217;arriver a faire se mettre a genoux et immobiliser une soumise puis la faire jouir en claquant des doigts sans la toucher, tout avec la voix.</p>
<p>Dans un autre domaine j&#8217;ai fait un petit jeu open source basé sur l&#8217;hypnose :<br />
<a href="http://ragemag.fr/oculus-rift-hypnose-virtuelle-ragemag-mystifier-jeu-video-45716/" title="http://ragemag.fr/oculus-rift-hypnose-virtuelle-ragemag-mystifier-jeu-video-45716/">http://ragemag.fr/oculus-rift-hypnose-virtuelle-ragemag-mystifier-jeu-video-45716/</a></p>
<p>Et un type que je recommande derren brown :<br />
<a href="https://www.youtube.com/user/OfficialDerren" title="https://www.youtube.com/user/OfficialDerren">https://www.youtube.com/user/OfficialDerren</a></p>
<p>Et pour finir une petite chanson :<br />
<iframe width="420" height="315" src="//www.youtube.com/embed/ElxbOr4b-vs" frameborder="0" allowfullscreen></iframe></p>


feed_id: http://sametmax.com/?p=15704
title: Rendez votre package exécutable avec __main__.py 5
uri: Rendez-votre-package-exécutable-avec-__main__-py-2-Recently-update
url: http://sametmax.com/rendez-votre-module-executable-avec-__main__-py/
content:
<p>Tout le monde connait le fichier <a href="http://sametmax.com/vous-pouvez-mettre-du-code-dans-__init__-py/">__init__.py</a>, mais <code>__main__.py</code> est moins connu.</p>
<p>Il permet de lancer du code si on tente d&#8217;exécuter un package (c&#8217;est à dire un dossier qui contient un fichier <code>__init__.py</code>):</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="bash" style="font-family:monospace;">$ <span style="color: #c20cb9; font-weight: bold;">tree</span> monpackage<span style="color: #000000; font-weight: bold;">/</span>
monpackakge<span style="color: #000000; font-weight: bold;">/</span>
├── __init__.py
└── __main__.py
&nbsp;
<span style="color: #000000;">0</span> directories, <span style="color: #000000;">2</span> files
$ <span style="color: #c20cb9; font-weight: bold;">cat</span> monpackage<span style="color: #000000; font-weight: bold;">/</span>__main__.py
print<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #ff0000;">'Hello :)'</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
$ python monpackage<span style="color: #000000; font-weight: bold;">/</span> <span style="color: #666666; font-style: italic;"># ceci est un dossier </span>
Hello :<span style="color: #7a0874; font-weight: bold;">&#41;</span></pre></td></tr></table></div>

<p>Le <code>__main__.py</code>  est aussi exécuté quand on fait <code>python -m monpackage</code>. </p>
<p>Notez que son exécution suppose l&#8217;import préalable du package, et que donc <code>__init__.py</code> sera toujours exécuté avant <code>__main__.py</code>. En revanche, faire juste <code>import monpackage</code> ne déclenche pas l&#8217;exécution de <code>__main__.py</code>.</p>
<p>Si vous zippez votre package et appelez la commande <code>python</code>, c&#8217;est aussi ce fichier qui sera exécuté. Pratique donc, pour faire un exécutable portable à peu de frais, tout en gardant la lib importable.</p>


feed_id: http://sametmax.com/?p=15727
title: Embeder Python dans du C ou C++ 6
uri: Embeder-Python-dans-du-C-ou-C-5-Recently-updated
url: http://sametmax.com/embeder-python-dans-du-c-ou-c/
content:
<p>L&#8217;implémentation de référence de Python est écrite en C, et son API est exposée et bien <a href="https://docs.python.org/2/c-api/">documentée</a>. Il est donc possible de créer des objets Python, charger un module Python ou exécuter une fonction Python depuis un code C/C++ et compiler tout ça.</p>
<p>Mettons que j&#8217;ai dans un fichier <code>biblio.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;">def</span> yolo<span style="color: black;">&#40;</span>arg<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">return</span> arg.<span style="color: black;">upper</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> + <span style="color: #483d8b;">' !!'</span></pre></td></tr></table></div>

<p>Je peux écrire un fichier <code>prog.c</code> qui l&#8217;utilise :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="c" style="font-family:monospace;"><span style="color: #339933;">#include &lt;Python.h&gt;</span>
&nbsp;
<span style="color: #993333;">int</span> main <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #666666; font-style: italic;">// PyObject est un wrapper Python autour des objets qu'on</span>
    <span style="color: #666666; font-style: italic;">// va échanger enter le C et Python.</span>
    PyObject <span style="color: #339933;">*</span>retour<span style="color: #339933;">,</span> <span style="color: #339933;">*</span>module<span style="color: #339933;">,</span> <span style="color: #339933;">*</span>fonction<span style="color: #339933;">,</span> <span style="color: #339933;">*</span>arguments<span style="color: #339933;">;</span>
    <span style="color: #993333;">char</span> <span style="color: #339933;">*</span>resultat<span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #666666; font-style: italic;">// Initialisation de l'interpréteur. A cause du GIL, on ne peut</span>
    <span style="color: #666666; font-style: italic;">// avoir qu'une instance de celui-ci à la fois.</span>
    Py_Initialize<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>   
&nbsp;
    <span style="color: #666666; font-style: italic;">// Import du script. </span>
    PySys_SetPath<span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;.&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// Le dossier en cours n'est pas dans le PYTHON PATH</span>
    module <span style="color: #339933;">=</span> PyImport_ImportModule<span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;biblio&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #666666; font-style: italic;">// Récupération de la fonction</span>
    fonction <span style="color: #339933;">=</span> PyObject_GetAttrString<span style="color: #009900;">&#40;</span>module<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;yolo&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #666666; font-style: italic;">// Création d'un PyObject de type string. Py_BuildValue peut créer</span>
    <span style="color: #666666; font-style: italic;">// tous les types de base Python. Voir :</span>
    <span style="color: #666666; font-style: italic;">// https://docs.python.org/2/c-api/arg.html#c.Py_BuildValue</span>
    arguments <span style="color: #339933;">=</span> Py_BuildValue<span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;(s)&quot;</span><span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;Leroy Jenkins&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> 
&nbsp;
    <span style="color: #666666; font-style: italic;">// Appel de la fonction.</span>
    retour <span style="color: #339933;">=</span> PyEval_CallObject<span style="color: #009900;">&#40;</span>fonction<span style="color: #339933;">,</span> arguments<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #666666; font-style: italic;">// Conversion du PyObject obtenu en string C</span>
    PyArg_Parse<span style="color: #009900;">&#40;</span>retour<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;s&quot;</span><span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>resultat<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000066;">printf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;Resultat: %s<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> resultat<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #666666; font-style: italic;">// On ferme cet interpréteur.</span>
    Py_Finalize<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> 
    <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>Là je mets du C, mais la seule vraie différence avec du C++, c&#8217;est qu&#8217;on aurait <code>cout</code> au lieu de <code>printf</code>.</p>
<p>Pour compiler tout ça, il faut les headers Python et un compilateur. Sous Ubuntu, c&#8217;est un simple :</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> python-dev <span style="color: #c20cb9; font-weight: bold;">gcc</span></pre></td></tr></table></div>

<p>Et on a tout nos <code>.h</code> dans /usr/include/python2.7. On gccise :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">gcc</span> -I<span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>include<span style="color: #000000; font-weight: bold;">/</span>python2.7 prog.c -lpython2.7 <span style="color: #660033;">-o</span> prog <span style="color: #660033;">-Wall</span>  <span style="color: #000000; font-weight: bold;">&amp;&amp;</span> .<span style="color: #000000; font-weight: bold;">/</span>prog</pre></td></tr></table></div>

<p>Même pas un warning, c&#8217;est beau.</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>prog
Resultat: LEROY JENKINS <span style="color: #000000; font-weight: bold;">!!</span></pre></td></tr></table></div>

<p>C&#8217;est un exemple simple, mais comme vous le savez je suis une grosse burne en C, donc je ne pourrai pas porter l&#8217;expérience plus loin.</p>
<p>Je ne le recommande pas pour rendre votre programme scriptable en Python. Il <a href="http://twistedmatrix.com/users/glyph/rant/extendit.html">vaut mieux</a> permettre à Python d&#8217;appeler votre code C dans ce cas. Des outils comme <a href="https://cffi.readthedocs.org/en/release-0.8/">cffi</a> rendent cela beaucoup plus facile et rentable que tout faire tout le taff à la main. D&#8217;ailleurs si quelqu&#8217;un est chaud pour faire un tuto sur cffi&#8230;</p>
<p>Non, c&#8217;est plus dans le cas où vous avez un programme C, un programme Python, et votre programme C veut utiliser le programme Python sans avoir à tout réécrire. Ou pour le cas où vous avez décidé d&#8217;écrire une grosse partie de votre programme en Python pour profiter de sa productivité, mais que vous ne pouvez pas installer Python sur la machine sur laquelle vous aller installer le programme. Bon, y a <a href="https://github.com/pyinstaller/pyinstaller/wiki">PyInstaller</a> et <a href="http://nuitka.net/">Nuitka</a> pour ça également hein, donc tentez avant de tout embeder comme un bourrin.</p>
<p>Ça reste intéressant de voir les entrailles de CPython et à quel point il joue bien avec les langages bas niveaux.</p>


feed_id: http://sametmax.com/?p=15736
title: Je me te tâte à arrêter le tuto Angular 34
uri: Je-me-te-tâte-à-arrêter-le-tuto-Angular-10-Recently-updated
url: http://sametmax.com/je-me-te-tate-a-arreter-le-tuto-angular/
content:
<p>Malgré les <a href="https://medium.com/este-js-framework/what-i-would-recommend-instead-of-angular-js-62b057d8a9e">critiques</a>, j&#8217;aime beaucoup AngularJS. Mais à <a href="http://www.i-programmer.info/news/167-javascript/7932-angularjs-20-is-radically-different-.html">l&#8217;annonce</a> de la version 2 d&#8217;Angular complètement incompatible avec la version 1, seulement quelques années après sa sortie, des questions <a href="http://www.quirksmode.org/blog/archives/2015/01/the_problem_wit.html">se sont posées</a> sur l&#8217;avenir du framework.</p>
<p>J&#8217;utilise AngularJS pour certains de mes projets, je suis payé pour former sur AngularJS et j&#8217;ai commencé à écrire <a href="http://sametmax.com/angularjs-pour-les-utilisateurs-de-jquery-partie-1/">un guide</a> sur le sujet.</p>
<p>Mais je me demande franchement si ça vaut le coup de s&#8217;investir plus.</p>
<p>Je vais continuer à l&#8217;utiliser pour mes projets actuels, tout en regardant du côté de la concurrence <a href="http://facebook.github.io/flux/">ici</a> et <a href="http://facebook.github.io/react/">là</a>.</p>
<p>Si j&#8217;écris l&#8217;article, ce n&#8217;est pas pour vous alarmer. Ni même pour vous dire &#8220;arrêtez d&#8217;utiliser Angular&#8221;. Je pense que la V1 va être maintenue par la communauté pendant des années.</p>
<p>Non, je me demande simplement si ça vaut le coup que je me casse le cul à finir le guide.</p>
<p>J&#8217;ai du travail à la pelle, le<a href="http://sametmax.com/un-gros-guide-bien-gras-sur-les-tests-unitaires-en-python-partie-1/"> guide sur les tests en Python</a>, <a href="https://github.com/sametmax/Django--an-app-at-a-time/tree/fran%C3%A7ais">Django une app à la fois</a>, 0bin à porter en Python 3&#8230;</p>
<p>Bref, est-ce que vous êtes toujours aussi intéressés par ce guide ?</p>


feed_id: http://sametmax.com/?p=15797
title: Utiliser requests de manière non bloquante facilement 7
uri: Utiliser-requests-de-manière-non-bloquante-facilement-4-Recently-u
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=15786
title: Gestion des erreurs en Python 9
uri: Gestion-des-erreurs-en-Python-6-Recently-updated
url: http://sametmax.com/gestion-des-erreurs-en-python/
content:
<p>Plus on code, plus on oublie ce que c&#8217;était quand on a débuté. Même moi, et pourtant je fais un gros effort pour essayer de me replonger dans cet état d&#8217;esprit.</p>
<p>Dernièrement j&#8217;ai eu plusieurs interactions qui m&#8217;ont mis un petit taquet derrière la tête :</p>
<blockquote><p>- &#8220;Mec, les exceptions, y a plein de personnes qui pigent pas.&#8221;</p>
<p>&#8211; &#8220;Nannnn, mais quand même, les exceptions&#8230;&#8221;</p>
<p>&#8211; &#8220;Si, les exceptions.&#8221;</p>
<p>&#8211; &#8220;Nan, vraiment ?&#8221;</p>
<p>&#8211; &#8220;Oui, vraiment.&#8221;</p></blockquote>
<p>Donc, back to black, et petit tour de la gestion d&#8217;erreur en Python.</p>
<p>Et de la musique.</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/8inJtTG_DuU?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>La notion d&#8217;exception</h2>
<p>Une exception est un mécanisme d&#8217;interruption du programme utilisé pour signaler que quelque chose d&#8217;anormal est en train de se produire.</p>
<p>On les rencontre dans de nombreux cas, mais souvent, c&#8217;est dans le cadre d&#8217;erreurs. Par exemple, Python va lever une exception dans les cas suivant :</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: #ff4500;">1</span> / <span style="color: #ff4500;">0</span> <span style="color: #808080; font-style: italic;"># division par zéro</span>
&nbsp;
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-2-b710d87c980c&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: #ff4500;">1</span> / <span style="color: #ff4500;">0</span>
<span style="color: #008000;">ZeroDivisionError</span>: integer division <span style="color: #ff7700;font-weight:bold;">or</span> modulo by zero
&nbsp;
<span style="color: #66cc66;">&gt;&gt;&gt;</span> l <span style="color: #66cc66;">=</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: black;">&#93;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> l<span style="color: black;">&#91;</span><span style="color: #ff4500;">100</span><span style="color: black;">&#93;</span> <span style="color: #808080; font-style: italic;"># dépassement d'un tableau</span>
&nbsp;
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-4-3e7ce3111e95&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>
    l<span style="color: black;">&#91;</span><span style="color: #ff4500;">100</span><span style="color: black;">&#93;</span>
<span style="color: #008000;">IndexError</span>: <span style="color: #008000;">list</span> index out of <span style="color: #008000;">range</span>
&nbsp;
<span style="color: #66cc66;">&gt;&gt;&gt;</span> d <span style="color: #66cc66;">=</span> <span style="color: black;">&#123;</span><span style="color: #483d8b;">'cle'</span>: <span style="color: #483d8b;">'valeur'</span><span style="color: black;">&#125;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> d<span style="color: black;">&#91;</span><span style="color: #483d8b;">'nope'</span><span style="color: black;">&#93;</span> <span style="color: #808080; font-style: italic;"># clé de dico inconnue</span>
&nbsp;
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-6-9d965227e4b0&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>
    d<span style="color: black;">&#91;</span><span style="color: #483d8b;">'nope'</span><span style="color: black;">&#93;</span>
<span style="color: #008000;">KeyError</span>: <span style="color: #483d8b;">'nope'</span>
&nbsp;
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff4500;">1</span> + <span style="color: #483d8b;">&quot;banane&quot;</span> <span style="color: #808080; font-style: italic;"># opération entre types incompatibles</span>
&nbsp;
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-7-5147635e41b3&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: #ff4500;">1</span> + <span style="color: #483d8b;">&quot;banane&quot;</span>
<span style="color: #008000;">TypeError</span>: unsupported operand <span style="color: #008000;">type</span><span style="color: black;">&#40;</span>s<span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">for</span> +: <span style="color: #483d8b;">'int'</span> <span style="color: #ff7700;font-weight:bold;">and</span> <span style="color: #483d8b;">'str'</span>
&nbsp;
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">import</span> nawak <span style="color: #808080; font-style: italic;"># ce module n'existe pas</span>
&nbsp;
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-c948b8798146&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: #ff7700;font-weight:bold;">import</span> nawak
<span style="color: #008000;">ImportError</span>: No module named nawak
&nbsp;
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #008000;">open</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'nawak'</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># le fichier n'existe pas</span>
&nbsp;
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-13-4d15cfd2ffd1&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;">open</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'nawak'</span><span style="color: black;">&#41;</span>
<span style="color: #008000;">IOError</span>: <span style="color: black;">&#91;</span>Errno <span style="color: #ff4500;">2</span><span style="color: black;">&#93;</span> No such <span style="color: #008000;">file</span> <span style="color: #ff7700;font-weight:bold;">or</span> directory: <span style="color: #483d8b;">'nawak'</span>
&nbsp;
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>nawak<span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># la variable n'existe pas</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-15-f47a27cedc12&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: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>nawak<span style="color: black;">&#41;</span>
<span style="color: #008000;">NameError</span>: name <span style="color: #483d8b;">'nawak'</span> <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #ff7700;font-weight:bold;">not</span> defined
&nbsp;
<span style="color: #66cc66;">&gt;&gt;&gt;</span> n a w a k <span style="color: #808080; font-style: italic;"># erreur de syntaxe</span>
  File <span style="color: #483d8b;">&quot;&lt;ipython-input-16-532bf025442e&gt;&quot;</span><span style="color: #66cc66;">,</span> line <span style="color: #ff4500;">1</span>
    n a w a k <span style="color: #808080; font-style: italic;"># erreur de syntaxe</span>
      ^
<span style="color: #008000;">SyntaxError</span>: invalid syntax
&nbsp;
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #008000;">int</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'a'</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># la valeur passée n'a aucun sens</span>
&nbsp;
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-17-b3c3f4515dd4&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;">int</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'a'</span><span style="color: black;">&#41;</span>
<span style="color: #008000;">ValueError</span>: invalid literal <span style="color: #ff7700;font-weight:bold;">for</span> <span style="color: #008000;">int</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">with</span> base <span style="color: #ff4500;">10</span>: <span style="color: #483d8b;">'a'</span></pre></td></tr></table></div>

<p>De base, il y a un paquet d&#8217;exceptions en Python, et celles fournies par défaut sont listées <a href="https://docs.python.org/2/library/exceptions.html#exceptions.TypeError">ici</a>.</p>
<p>Malgré l&#8217;abondance de ces exceptions, vous pouvez remarquer un motif récurrent quand Python crash et affiche l&#8217;erreur :</p>
<pre>Gros pâté de texte.
Gros pâté de texte.
Gros pâté de texte.
NomDeLExceptionError: description de l'erreur.</pre>
<p>En effet, non seulement une exception interrompt le programme, mais elle collecte des informations sur la source de l&#8217;erreur afin qu&#8217;au moment où ça crash, le développeur ait de quoi déboguer.</p>
<p>Une exception va donc normalement déclencher un affichage à la fin avec toutes ces infos, et sur la dernière ligne, le type de l&#8217;exception (ValueError, IndexError, etc) ainsi qu&#8217;une description de ce qui a causé l&#8217;erreur.</p>
<p>Néanmoins, le plus intéressant est ce qu&#8217;il y a au dessus : le gros pâté de texte. C&#8217;est ce qu&#8217;on appelle une stack trace, et ça représente la pile d&#8217;appels qui ont amené à cette erreur. Chaque ligne de la stack trace va vous donner le chemin d&#8217;un fichier de code, et une ligne.</p>
<p>Une erreur se lit donc à l&#8217;envers, de bas en haut.</p>
<p>Vous lisez d&#8217;abord le nom de l&#8217;erreur et sa cause, puis, vous remontez la stack trace ligne à ligne, pour essayer de trouver quelle ligne de quel fichier de code vous devez déboguer.</p>
<p>Par exemple, si vous avez un fichier <code>wololo.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;">def</span> une_fonction<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #ff4500;">1</span> / <span style="color: #ff4500;">0</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> une_autre_fonction<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    une_fonction<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
une_autre_fonction<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Lancer ce script va vous pondre :</p>
<pre>
Traceback (most recent call last):
  File "wololo.py", line 7, in <module>
    une_autre_fonction()
  File "wololo.py", line 5, in une_autre_fonction
    une_fonction()
  File "wololo.py", line 2, in une_fonction
    return 1 / 0
ZeroDivisionError: integer division or modulo by zero
</pre>
<p>On le lit de bas en haut :</p>
<pre>ZeroDivisionError: integer division or modulo by zero</pre>
<p>Ok, donc c&#8217;est une erreur de division par 0.</p>
<pre>  File "wololo.py", line 2, in une_fonction
    return 1 / 0</pre>
<p>Elle a lieu dans mon fichier <code>wololo.py</code> à la ligne 2.</p>
<p>Mais visiblement, ce qui déclenche tout le bordel, c&#8217;est que la fonction contenant cette ligne est appelé à la ligne 5 :</p>
<pre>
  File "wololo.py", line 5, in une_autre_fonction
    une_fonction()</pre>
<p>Qui est elle même appelée à la ligne 7 :</p>
<pre>
  File "wololo.py", line 7, in <module>
    une_autre_fonction()
</pre>
<p>Avec ces infos, on peut prendre une décision : aller ligne 2 pour corriger un bug, ou aller ligne 5, ou 7 pour retirer l&#8217;appel qui cause le déclenchement du code fautif.</p>
<p>Dans ce cas, vous pourriez vous dire qu&#8217;il faut retirer la division par 0, et que les premières ligne de la stack trace ne servent à rien.</p>
<p>Mais imaginez que je change mon 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;">def</span> une_fonction<span style="color: black;">&#40;</span>diviseur<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #ff4500;">1</span> / diviseur
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> une_autre_fonction<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    une_fonction<span style="color: black;">&#40;</span>diviseur<span style="color: #66cc66;">=</span><span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>
&nbsp;
une_autre_fonction<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>A ce moment là, mon stack trace sera :</p>
<pre>Traceback (most recent call last):
  File "wololo.py", line 7, in <module>
    une_autre_fonction()
  File "wololo.py", line 5, in une_autre_fonction
    une_fonction(diviseur=0)
  File "wololo.py", line 2, in une_fonction
    return 1 / diviseur
ZeroDivisionError: integer division or modulo by zero</pre>
<p>Et là, on ne veut pas changer la ligne 2, on veut changer la ligne 5, car c&#8217;est ce paramètre qui fait qu&#8217;à la ligne 2 on a une division par 0.</p>
<p>La stack trace permet donc de remonter la chaîne de causalité de vos erreurs.</p>
<h2>Lever ses propres exceptions</h2>
<p>Quand une exception est activée, on dit qu&#8217;elle est &#8220;levée&#8221;.</p>
<p>Python va lever des exceptions de lui-même, par exemple en cas d&#8217;erreurs, mais on peut aussi lever soi-même des exceptions en faisant <code>raise NomDeLException("Message")</code>.</p>
<p>Par exemple, vous avez une fonction qui n&#8217;accepte en paramètre que comme valeur 1, 2 ou 3. Vous savez que si un utilisateur rentre quelque chose d&#8217;autre, ça va tout faire merder.</p>
<p>Vous pouvez faire ceci :</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> votre_super_fonction<span style="color: black;">&#40;</span>param<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">if</span> param <span style="color: #ff7700;font-weight:bold;">not</span> <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: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">raise</span> <span style="color: #008000;">ValueError</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;'param' can only be either 1, 2 or 3&quot;</span><span style="color: black;">&#41;</span>
    <span style="color: #808080; font-style: italic;"># reste du code</span></pre></td></tr></table></div>

<p>Ainsi, si quelqu&#8217;un passe un mauvais paramètre, il est immédiatement alerté :</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> votre_super_fonction<span style="color: black;">&#40;</span><span style="color: #ff4500;">4</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-3-bcd6e8653c83&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>
    votre_super_fonction<span style="color: black;">&#40;</span><span style="color: #ff4500;">4</span><span style="color: black;">&#41;</span>
  File <span style="color: #483d8b;">&quot;&lt;ipython-input-2-46fc7cd18c42&gt;&quot;</span><span style="color: #66cc66;">,</span> line <span style="color: #ff4500;">3</span><span style="color: #66cc66;">,</span> <span style="color: #ff7700;font-weight:bold;">in</span> votre_super_fonction
    <span style="color: #ff7700;font-weight:bold;">raise</span> <span style="color: #008000;">ValueError</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;'param' can only be either 1, 2 or 3&quot;</span><span style="color: black;">&#41;</span>
<span style="color: #008000;">ValueError</span>: <span style="color: #483d8b;">'param'</span> can only be either <span style="color: #ff4500;">1</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">2</span> <span style="color: #ff7700;font-weight:bold;">or</span> <span style="color: #ff4500;">3</span></pre></td></tr></table></div>

<p>Attention : le message ne peut pas contenir de caractères non-ASCII. Oubliez les accents.</p>
<h2>Attraper une exception</h2>
<p>Les exceptions ne sont pas un simple mécanisme de debuggage. Elles servent d&#8217;abord et avant tout à gérer les cas exceptionnels, et on peut donc les détecter, et réagir quand elles surviennent, à l&#8217;aide de l&#8217;instruction <code>try/except</code>.</p>
<p>Cela s&#8217;utilise en enrobant les lignes qui peuvent lever une exception :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">    <span style="color: #ff7700;font-weight:bold;">try</span>:
        <span style="color: #808080; font-style: italic;"># lignes qui peuvent</span>
        <span style="color: #808080; font-style: italic;"># lever une exception</span>
    <span style="color: #ff7700;font-weight:bold;">except</span> NomException:
        <span style="color: #808080; font-style: italic;"># faire un truc si l'exception se déclenche</span></pre></td></tr></table></div>

<p>Quand vous attrapez une exception, le programme ne plante pas. A la place, le bloc <code>except</code> correspondant au nom de l&#8217;exception est appelée.</p>
<p>Bien entendu, si une exception qui ne porte pas ce nom est levée, le programme plante.</p>
<p>Par exemple :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">    <span style="color: #808080; font-style: italic;"># i est définit plus haut</span>
    personnages <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span><span style="color: #483d8b;">'iron'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'super'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'bat'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'clepto'</span><span style="color: black;">&#93;</span>
    <span style="color: #ff7700;font-weight:bold;">try</span>:
        resultat <span style="color: #66cc66;">=</span> personnages<span style="color: black;">&#91;</span>i<span style="color: black;">&#93;</span>
    <span style="color: #808080; font-style: italic;"># i est plus grand que la taille du tableau</span>
    <span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">IndexError</span>:
        resultat <span style="color: #66cc66;">=</span> <span style="color: #008000;">None</span></pre></td></tr></table></div>

<p>Si <code>i</code> est plus grand que la taille de la liste, Python va lever une <code>IndexError</code>, qui sera attrapée. Le programme ne plantera pas, et <code>resultat</code> sera égal à <code>None</code>.</p>
<p>Si <code>i</code> est de type string, Python va lever une <code>TypeError</code>, et le programme va planter.</p>
<p>Cela suppose de savoir le nom de l&#8217;erreur qu&#8217;on veut gérer. Je recommande donc de tester le cas foireux dans le shell auparavant.</p>
<p>On peut gérer plusieurs exceptions avec un seul bloc :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">    <span style="color: #ff7700;font-weight:bold;">try</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> personnages<span style="color: black;">&#91;</span><span style="color: #ff4500;">100</span> / i<span style="color: black;">&#93;</span>
    <span style="color: #808080; font-style: italic;"># est exécuté pour ces deux exceptions</span>
    <span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">IndexError</span><span style="color: #66cc66;">,</span> <span style="color: #008000;">ZeroDivisionError</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">None</span>
    <span style="color: #808080; font-style: italic;"># est exécuté pour cette exception</span>
    <span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">KeyError</span>:
        <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Qui est le bâtard qui a remplacé ma &quot;</span>
              <span style="color: #483d8b;">&quot;liste par un dico dans mon dos ?&quot;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<h2>Hiérarchie des exceptions</h2>
<p>Les exceptions sont des classes. Et si vous avez lu notre <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/">dossier sur la POO</a>, vous savez que les classes peuvent hériter d&#8217;autres classes.</p>
<p>C&#8217;est le cas des exceptions. Celles intégrées à Python suivent la hiérarchie suivante :</p>
<pre>
BaseException
 +-- SystemExit
 +-- KeyboardInterrupt
 +-- GeneratorExit
 +-- Exception
      +-- StopIteration
      +-- ArithmeticError
      |    +-- FloatingPointError
      |    +-- OverflowError
      |    +-- ZeroDivisionError
      +-- AssertionError
      +-- AttributeError
      +-- BufferError
      +-- EnvironmentError
      |    +-- IOError
      |    +-- OSError
      |         +-- WindowsError (Windows)
      |         +-- VMSError (VMS)
      +-- EOFError
      +-- ImportError
      +-- LookupError
      |    +-- IndexError
      |    +-- KeyError
      +-- MemoryError
      +-- NameError
      |    +-- UnboundLocalError
      +-- ReferenceError
      +-- RuntimeError
      |    +-- NotImplementedError
      +-- SyntaxError
      |    +-- IndentationError
      |         +-- TabError
      +-- SystemError
      +-- TypeError
      +-- ValueError
      |    +-- UnicodeError
      |         +-- UnicodeDecodeError
      |         +-- UnicodeEncodeError
      |         +-- UnicodeTranslateError
      +-- Warning
           +-- DeprecationWarning
           +-- PendingDeprecationWarning
           +-- RuntimeWarning
           +-- SyntaxWarning
           +-- UserWarning
           +-- FutureWarning
           +-- ImportWarning
           +-- UnicodeWarning
           +-- BytesWarning
</pre>
<p>Par exemple, <code>IndexError</code> et <code>KeyError</code> héritent toutes les deux de <code>LookupError</code>.</p>
<p>Donc si vous faites :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">    <span style="color: #ff7700;font-weight:bold;">try</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> personnages<span style="color: black;">&#91;</span>i<span style="color: black;">&#93;</span>
    <span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">LookupError</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">None</span></pre></td></tr></table></div>

<p>Vous attrapez à la fois les exceptions de type <code>IndexError</code> et <code>KeyError</code>.</p>
<p><code>LookupError</code> hérite de <code>Exception</code>, dont hérite la plupart des exceptions en Python. Donc si vous faites :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">    <span style="color: #ff7700;font-weight:bold;">try</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> personnages<span style="color: black;">&#91;</span><span style="color: #ff4500;">100</span> / i<span style="color: black;">&#93;</span>
    <span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">Exception</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">None</span></pre></td></tr></table></div>

<p>Vous allez attraper <code>LookupError</code>, <code>IndexError</code>, <code>ZeroDivisionError</code> et probablement tout un tas de trucs auxquels vous n&#8217;avez pas pensé ce qui peut potentiellement un jour masquer un bug dans votre programme.</p>
<p>Donc <strong>gérez toujours l&#8217;erreur au plus proche de la logique de votre programme</strong>.</p>
<p>Il est d&#8217;ailleurs possible de dire à Python &#8220;tu m&#8217;attrapes tout&#8221; en omettant le nom de l&#8217;exception :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">    <span style="color: #ff7700;font-weight:bold;">try</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> personnages<span style="color: black;">&#91;</span><span style="color: #ff4500;">100</span> / i<span style="color: black;">&#93;</span>
    <span style="color: #ff7700;font-weight:bold;">except</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">None</span></pre></td></tr></table></div>

<p>C&#8217;est généralement une mauvaise idée car si il arrive une erreur que vous n&#8217;avez pas prévue, la close <code>except</code> s&#8217;activera, masquant l&#8217;erreur, et ne vous donnera jamais la chance de découvrir le problème.</p>
<p>Sachez également que vous n&#8217;êtes pas limité à la hiérarchie offerte par Python. Vous pouvez créer vos propres exceptions en héritant d&#8217;une des exceptions existantes de 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;">class</span> MonProjetError<span style="color: black;">&#40;</span><span style="color: #008000;">Exception</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">pass</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> MonTraitementError<span style="color: black;">&#40;</span>MonProjetError<span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">pass</span></pre></td></tr></table></div>

<p>C&#8217;est généralement une bonne idée quand vous créez une lib et que vous voulez permettre aux utilisateurs de votre bibliothèque de pouvoir filtrer les exceptions levées par votre code uniquement.</p>
<p>Néanmoins, dans ce cas, choisissez intelligemment les parents de vos exceptions personnalisées. Chaque exception de Python est porteuse de sens. <code>TypeError</code> est levée pour une erreur de type, <code>IOError</code> pour une erreur d&#8217;entrée/sortie, etc. Il est logique qu&#8217;un développeur s&#8217;attende à pouvoir les attraper selon ce sens.</p>
<p>Heureusement, on peut hériter de plusieurs exceptions :</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> MonProjetError<span style="color: black;">&#40;</span><span style="color: #008000;">Exception</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">pass</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> MonTraitementError<span style="color: black;">&#40;</span>MonProjetError<span style="color: #66cc66;">,</span> <span style="color: #008000;">TypeError</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">pass</span></pre></td></tr></table></div>

<p>Du coup, si quelqu&#8217;un essaye d&#8217;attraper <code>MonTraitementError</code> ou <code>TypeError</code> ou <code>MonProjetError</code> selon ce qu&#8217;il désire exprimer, ça marchera.</p>
<p>En effet, les exceptions sont une forme d&#8217;expression :</p>
<ul>
<li>Celui qui lève l&#8217;exception dit explicitement ce qui peut merder : quand on lit son code, on comprend les cas d&#8217;erreurs.</li>
<li>Celui qui l&#8217;attrape dit explicitement ce qu&#8217;il veut gérer : quand on lit son code, on comprend l&#8217;objectif.</li>
<li>Python dit explicitement ce qui a foiré. Quand on lit la stack trace, on comprend ce qui a merdé.</li>
</ul>
<p><strong>Vous communiquez en utilisant des exceptions entre développeurs et utilisateurs du code.</strong></p>
<h2>Finally et else</h2>
<p><code>try/except</code> peut être complété par deux autres mots clés : <code>finally</code> et <code>else</code>.</p>
<p><code>else</code> est le bloc exécuté si aucune exception n&#8217;est levée :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">    <span style="color: #ff7700;font-weight:bold;">try</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> personnages<span style="color: black;">&#91;</span><span style="color: #ff4500;">100</span> / i<span style="color: black;">&#93;</span>
    <span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">IndexError</span><span style="color: #66cc66;">,</span> <span style="color: #008000;">ZeroDivisionError</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">None</span>
    <span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">KeyError</span>:
        <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Qui est le bâtard qui a remplacé ma &quot;</span>
              <span style="color: #483d8b;">&quot;liste par un dico dans mon dos ?&quot;</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">else</span>:
        <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Bon en fait tout va bien'</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p><code>finally</code> est un bloc qui est exécuté après que tous les autres blocs aient été exécutés, peu importe qu&#8217;il y ait eu une exception ou non, et <strong>même si le programme crash</strong>.</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">    <span style="color: #ff7700;font-weight:bold;">try</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> personnages<span style="color: black;">&#91;</span><span style="color: #ff4500;">100</span> / i<span style="color: black;">&#93;</span>
    <span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">IndexError</span><span style="color: #66cc66;">,</span> <span style="color: #008000;">ZeroDivisionError</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">None</span>
    <span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">KeyError</span>:
        <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Qui est le bâtard qui a remplacé ma &quot;</span>
              <span style="color: #483d8b;">&quot;liste par un dico dans mon dos ?&quot;</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">finally</span>:
        <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Rosebud !'</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Dans notre cas, peu importe ce qui se passe dans le bloc <code>try/except</code>, <code>Rosebud !</code> est toujours affiché.</p>
<p><code>finally</code> n&#8217;est pas à l&#8217;épreuve des balles, si on crash l’interpréteur violemment (ou que vous débranchez la prise du serveur :)), il ne vous sauvera pas. Mais il permet de gérer la plupart des cas extrêmes.</p>
<p>Ah, oui, au fait, si vous utilisez <code>finally</code>, <code>except</code> n&#8217;est pas obligatoire.</p>
<h2>Quand utiliser try, except, else et finally ?</h2>
<p>On utilisera <code>try/except</code> d&#8217;abord et avant tout pour gérer les erreurs sur laquelle on a pas de controle.</p>
<p>Par exemple, vous téléchargez une document depuis le Web :</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;">import</span> <span style="color: #dc143c;">urllib</span>.<span style="color: black;">request</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> fichier_recu<span style="color: #66cc66;">,</span> headers <span style="color: #66cc66;">=</span> <span style="color: #dc143c;">urllib</span>.<span style="color: black;">request</span>.<span style="color: black;">urlretrieve</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'http://www.sudinfo.be/sites/default/files/imagecache/pagallery_450x300/1365338424_B9765144Z.1_20121219124926_000_GOJDROM6.1-0.png'</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Ca va marcher la plupart du temps. Et puis un jour, le réseau va sauter, et ça va plus marcher :</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> fichier_recu<span style="color: #66cc66;">,</span> headers <span style="color: #66cc66;">=</span> <span style="color: #dc143c;">urllib</span>.<span style="color: black;">request</span>.<span style="color: black;">urlretrieve</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'http://www.sudinfo.be/sites/default/files/imagecache/pagallery_450x300/1365338424_B9765144Z.1_20121219124926_000_GOJDROM6.1-0.png'</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-10-0f41d15585f0&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>
    fichier_recu<span style="color: #66cc66;">,</span> headers <span style="color: #66cc66;">=</span> <span style="color: #dc143c;">urllib</span>.<span style="color: black;">request</span>.<span style="color: black;">urlretrieve</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'http://www.sudinfo.be/sites/default/files/imagecache/pagallery_450x300/1365338424_B9765144Z.1_20121219124926_000_GOJDROM6.1-0.png'</span><span style="color: black;">&#41;</span>
  File <span style="color: #483d8b;">&quot;/usr/lib/python3.4/urllib/request.py&quot;</span><span style="color: #66cc66;">,</span> line <span style="color: #ff4500;">178</span><span style="color: #66cc66;">,</span> <span style="color: #ff7700;font-weight:bold;">in</span> urlretrieve
    <span style="color: #ff7700;font-weight:bold;">with</span> contextlib.<span style="color: black;">closing</span><span style="color: black;">&#40;</span>urlopen<span style="color: black;">&#40;</span>url<span style="color: #66cc66;">,</span> data<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">as</span> fp:
  File <span style="color: #483d8b;">&quot;/usr/lib/python3.4/urllib/request.py&quot;</span><span style="color: #66cc66;">,</span> line <span style="color: #ff4500;">153</span><span style="color: #66cc66;">,</span> <span style="color: #ff7700;font-weight:bold;">in</span> urlopen
    <span style="color: #ff7700;font-weight:bold;">return</span> opener.<span style="color: #008000;">open</span><span style="color: black;">&#40;</span>url<span style="color: #66cc66;">,</span> data<span style="color: #66cc66;">,</span> timeout<span style="color: black;">&#41;</span>
  File <span style="color: #483d8b;">&quot;/usr/lib/python3.4/urllib/request.py&quot;</span><span style="color: #66cc66;">,</span> line <span style="color: #ff4500;">455</span><span style="color: #66cc66;">,</span> <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">open</span>
    response <span style="color: #66cc66;">=</span> <span style="color: #008000;">self</span>._open<span style="color: black;">&#40;</span>req<span style="color: #66cc66;">,</span> data<span style="color: black;">&#41;</span>
  File <span style="color: #483d8b;">&quot;/usr/lib/python3.4/urllib/request.py&quot;</span><span style="color: #66cc66;">,</span> line <span style="color: #ff4500;">473</span><span style="color: #66cc66;">,</span> <span style="color: #ff7700;font-weight:bold;">in</span> _open
    <span style="color: #483d8b;">'_open'</span><span style="color: #66cc66;">,</span> req<span style="color: black;">&#41;</span>
  File <span style="color: #483d8b;">&quot;/usr/lib/python3.4/urllib/request.py&quot;</span><span style="color: #66cc66;">,</span> line <span style="color: #ff4500;">433</span><span style="color: #66cc66;">,</span> <span style="color: #ff7700;font-weight:bold;">in</span> _call_chain
    result <span style="color: #66cc66;">=</span> func<span style="color: black;">&#40;</span>*args<span style="color: black;">&#41;</span>
  File <span style="color: #483d8b;">&quot;/usr/lib/python3.4/urllib/request.py&quot;</span><span style="color: #66cc66;">,</span> line <span style="color: #ff4500;">1258</span><span style="color: #66cc66;">,</span> <span style="color: #ff7700;font-weight:bold;">in</span> http_open
    <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>.<span style="color: black;">do_open</span><span style="color: black;">&#40;</span>http.<span style="color: black;">client</span>.<span style="color: black;">HTTPConnection</span><span style="color: #66cc66;">,</span> req<span style="color: black;">&#41;</span>
  File <span style="color: #483d8b;">&quot;/usr/lib/python3.4/urllib/request.py&quot;</span><span style="color: #66cc66;">,</span> line <span style="color: #ff4500;">1235</span><span style="color: #66cc66;">,</span> <span style="color: #ff7700;font-weight:bold;">in</span> do_open
    <span style="color: #ff7700;font-weight:bold;">raise</span> URLError<span style="color: black;">&#40;</span>err<span style="color: black;">&#41;</span>
URLError: <span style="color: #66cc66;">&lt;</span>urlopen error <span style="color: black;">&#91;</span>Errno -<span style="color: #ff4500;">2</span><span style="color: black;">&#93;</span> Name <span style="color: #ff7700;font-weight:bold;">or</span> service <span style="color: #ff7700;font-weight:bold;">not</span> known<span style="color: #66cc66;">&gt;</span></pre></td></tr></table></div>

<p>On va donc gérer l&#8217;exception (et beaucoup d&#8217;autres, le réseau ça foire tout le temps) :</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;">try</span>:
    fichier_recu<span style="color: #66cc66;">,</span> headers <span style="color: #66cc66;">=</span> <span style="color: #dc143c;">urllib</span>.<span style="color: black;">request</span>.<span style="color: black;">urlretrieve</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'http://www.sudinfo.be/sites/default/files/imagecache/pagallery_450x300/1365338424_B9765144Z.1_20121219124926_000_GOJDROM6.1-0.png'</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #dc143c;">urllib</span>.<span style="color: black;">URLError</span>:
    <span style="color: #808080; font-style: italic;"># faire un truc</span></pre></td></tr></table></div>

<p>Parmi les choses à faire : réessayer plus tard, tenter de redémarrer la carte réseau, changer d&#8217;URL&#8230;</p>
<p>Un autre raison d&#8217;utiliser <code>try/except</code> est pour enregistrer une trace des erreurs.</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;">try</span>:
    url <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">'http://www.sudinfo.be/sites/default/files/imagecache/pagallery_450x300/1365338424_B9765144Z.1_20121219124926_000_GOJDROM6.1-0.png'</span>
    fichier_recu<span style="color: #66cc66;">,</span> headers <span style="color: #66cc66;">=</span> <span style="color: #dc143c;">urllib</span>.<span style="color: black;">request</span>.<span style="color: black;">urlretrieve</span><span style="color: black;">&#40;</span>url<span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #dc143c;">urllib</span>.<span style="color: black;">URLError</span>:
    <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;">'/tmp/errors.log'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'a'</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">as</span> f:
        f.<span style="color: black;">write</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;L'URL '%s' est inacessible&quot;</span> % url<span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>On peut le faire avec le module <code>logging</code>, ou envoyer un mail ou un SMS d&#8217;alerte&#8230;</p>
<p>Proposer un comportement par défaut est aussi très courant.</p>
<p>Par exemple, vous voulez récupérer le premier élément d&#8217;une liste, mais si la liste est vide, récupérer <code>None</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;">try</span>:
    resultat <span style="color: #66cc66;">=</span> liste<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span>
<span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">IndexError</span>:
    resultat <span style="color: #66cc66;">=</span> <span style="color: #008000;">None</span></pre></td></tr></table></div>

<p>Ce cas d&#8217;usage est typique de Python. Dans d&#8217;autres langage, on regarderait si le tableau est vide :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">if</span> liste:
    resultat <span style="color: #66cc66;">=</span> liste<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span>
<span style="color: #ff7700;font-weight:bold;">else</span>:
    resultat <span style="color: #66cc66;">=</span> <span style="color: #008000;">None</span></pre></td></tr></table></div>

<p>C&#8217;est typiquement la philosophie Java : &#8220;Watch before you leap&#8221; (WBYL). Soit &#8220;Regardez où vous mettez les pieds&#8221;.</p>
<p>En Python, la philosophie est &#8220;It&#8217;s easier to ask for forgiveness than permission&#8221; (EAFP). Soit &#8220;il est plus facile de demander pardon que la permission&#8221;.</p>
<p>La raison est que les exceptions sont très rapides en Python, et permettent de gérer plein de cas d&#8217;un coup.</p>
<p>Par exemple, dans le cas :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">if</span> conteneur:
    resultat <span style="color: #66cc66;">=</span> conteneur<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span>
<span style="color: #ff7700;font-weight:bold;">else</span>:
    resultat <span style="color: #66cc66;">=</span> <span style="color: #008000;">None</span></pre></td></tr></table></div>

<p>Que se passe-t-il si conteneur peut être un dictionnaire ou une liste ? C&#8217;est possible en Python du fait du <a href="http://sametmax.com/quest-ce-que-le-duck-typing-et-a-quoi-ca-sert/">duck typing</a>.</p>
<p>Il faut tester deux cas :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">if</span> conteneur <span style="color: #ff7700;font-weight:bold;">and</span> <span style="color: #ff4500;">0</span> <span style="color: #ff7700;font-weight:bold;">in</span> conteneur:
    resultat <span style="color: #66cc66;">=</span> conteneur<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span>
<span style="color: #ff7700;font-weight:bold;">else</span>:
    resultat <span style="color: #66cc66;">=</span> <span style="color: #008000;">None</span></pre></td></tr></table></div>

<p>Avec une exception, on teste un seul cas :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">try</span>:
    resultat <span style="color: #66cc66;">=</span> conteneur<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span>
<span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">LookupError</span>:
    resultat <span style="color: #66cc66;">=</span> <span style="color: #008000;">None</span></pre></td></tr></table></div>

<p>Là c&#8217;est un cas simple, mais sur des cas complexes comme les fichiers, c&#8217;est très utile :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">try</span>:
    fichier <span style="color: #66cc66;">=</span> <span style="color: #008000;">open</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'/tmp/fichier'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'w'</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">IOError</span><span style="color: #66cc66;">,</span> <span style="color: #008000;">OSError</span>:
    <span style="color: #808080; font-style: italic;"># gérer l'erreur</span></pre></td></tr></table></div>

<p>Si je devais faire ça avec des <code>if</code>, il faudrait :</p>
<ul>
<li>Vérifier que le fichier existe.</li>
<li>Vérifier que le fichier est un fichier et non un dossier.</li>
<li>Vérifier que j&#8217;ai les permissions d&#8217;écrire sur le fichier.</li>
<li>Vérifier que j&#8217;ai les permissions de traverser les dossiers parents.</li>
<li>Vérifier que personne n&#8217;a ouvert le fichier en écriture avant.</li>
</ul>
<p>C&#8217;est relou. Mais en prime, entre chaque vérification du <code>if</code> s&#8217;écoule quelques nanosecondes durant lequelles l&#8217;état de mon fichier a pu changer. Un autre programme a pu changer les permissions, créer un fichier avec le même nom, etc. Arrivé à la fin du <code>if</code>, on n&#8217;a pas la garantie que les vérifications du début du <code>if</code> sont toujours d&#8217;actualité.</p>
<p><code>try/except</code> évite ce problème qu&#8217;on appelle des &#8220;race conditions&#8221; : on essaye d&#8217;abord, et ensuite si ça foire, on analyse pourquoi. Comme en drague.</p>
<p>Enfin on va utiliser <code>finally</code> pour faire du nettoyage : fermer un fichier, fermer une connexion à une base de données, une socket, supprimer un fichier temporaire. Bref, tout ce qu&#8217;on veut qui arrive, même si notre code se vautre.</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">try</span>:
    fichier <span style="color: #66cc66;">=</span> <span style="color: #008000;">open</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'/tmp/fichier'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'w'</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">IOError</span><span style="color: #66cc66;">,</span> <span style="color: #008000;">OSError</span>:
    <span style="color: #808080; font-style: italic;"># gérer l'erreur</span>
<span style="color: #ff7700;font-weight:bold;">else</span>:
    <span style="color: #808080; font-style: italic;"># faire un truc avec le fichier</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># on essaye toujours de fermer notre fichier</span>
<span style="color: #ff7700;font-weight:bold;">finally</span>:
    <span style="color: #ff7700;font-weight:bold;">try</span>:
        fichier.<span style="color: black;">close</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># le fichier n'a jamais été ouvert et</span>
    <span style="color: #808080; font-style: italic;"># la variable n'existe pas</span>
    <span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">NameError</span>:
        <span style="color: #ff7700;font-weight:bold;">pass</span></pre></td></tr></table></div>

<h2>with</h2>
<p>Comme vous avez pu le constater, gérer proprement les erreurs, ça peut devenir vite chiant. Pour cette raison, beaucoup de <a href="http://sametmax.com/les-context-managers-et-le-mot-cle-with-en-python/">context managers</a> servent à gérer les cas les plus courants.</p>
<p>Typiquement :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">try</span>:
    fichier <span style="color: #66cc66;">=</span> <span style="color: #008000;">open</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'/tmp/fichier'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'w'</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">IOError</span><span style="color: #66cc66;">,</span> <span style="color: #008000;">OSError</span>:
    <span style="color: #808080; font-style: italic;"># gérer l'erreur</span>
<span style="color: #ff7700;font-weight:bold;">else</span>:
    <span style="color: #808080; font-style: italic;"># faire un truc avec le fichier</span>
<span style="color: #ff7700;font-weight:bold;">finally</span>:
    <span style="color: #ff7700;font-weight:bold;">try</span>:
        fichier.<span style="color: black;">close</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">NameError</span>:
        <span style="color: #ff7700;font-weight:bold;">pass</span></pre></td></tr></table></div>

<p>Peut être remplacé par :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">try</span>:
    <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;">'/tmp/fichier'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'w'</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">as</span> fichier:
        <span style="color: #808080; font-style: italic;"># faire un truc avec le fichier</span>
<span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">IOError</span><span style="color: #66cc66;">,</span> <span style="color: #008000;">OSError</span>:
    <span style="color: #808080; font-style: italic;"># gérer l'erreur</span></pre></td></tr></table></div>

<p>Ce qui est quand même vachement plus court. Le context manager va s&#8217;occuper de la fermeture du fichier pour nous proprement. Cet article est déjà long, donc je ne vais pas rentrer en détail sur <code>with</code>, mais sachez que beaucoup d&#8217;objets qui demandent une fermeture peuvent être traités comme ça.</p>
<h2>Bubbling</h2>
<p>Une chose qui échappe généralement aux débutants quand ils commencent à utiliser les exceptions, c&#8217;est qu&#8217;elles bubblent, c&#8217;est à dire qu&#8217;elles remontent comme une bulle, de bloc en bloc, jusqu&#8217;à la racine du programme.</p>
<p>Si j&#8217;ai :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">if</span> truc:
    <span style="color: #ff7700;font-weight:bold;">if</span> machin:
        <span style="color: #ff7700;font-weight:bold;">for</span> bidule <span style="color: #ff7700;font-weight:bold;">in</span> chose:
            <span style="color: #ff7700;font-weight:bold;">raise</span> MaisAieuuuuuError<span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Ca fait mal t'es con&quot;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Mon programme ne va PAS planter à la ligne <code>raise MaisAieuuuuuError("Ca fait mal t'es con")</code>.</p>
<p>A la place, l&#8217;erreur va remonter en dehors de la boucle. Si elle n&#8217;est pas attrapée, elle va remonter en dehors du premier <code>if</code>. Si elle n&#8217;est pas attrapée, elle va remonter en dehors du second <code>if</code>, et enfin, si elle vraiment, mais alors vraiment pas attrapée, Python va crasher, et montrer une belle stack trace.</p>
<p>Ça veut dire que vous pouvez arrêter l&#8217;exception à plusieurs endroits dans le programme :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">if</span> truc:
    <span style="color: #ff7700;font-weight:bold;">if</span> machin:
        <span style="color: #ff7700;font-weight:bold;">for</span> bidule <span style="color: #ff7700;font-weight:bold;">in</span> chose:
            <span style="color: #ff7700;font-weight:bold;">try</span>:
                <span style="color: #ff7700;font-weight:bold;">raise</span> MaisAieuuuuuError<span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Ca fait mal t'es con&quot;</span><span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">except</span> MaisAieuuuuuError:
                <span style="color: #808080; font-style: italic;"># faire un truc</span></pre></td></tr></table></div>

<p>Dans ce cas, la boucle va continuer à tourner après la première erreur, et faire un <code>try/except</code> à chaque tour de boucle.</p>
<p>Mais si vous faites :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">if</span> truc:
    <span style="color: #ff7700;font-weight:bold;">if</span> machin:
        <span style="color: #ff7700;font-weight:bold;">try</span>
            <span style="color: #ff7700;font-weight:bold;">for</span> bidule <span style="color: #ff7700;font-weight:bold;">in</span> chose:
                <span style="color: #ff7700;font-weight:bold;">raise</span> MaisAieuuuuuError<span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Ca fait mal t'es con&quot;</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">except</span> MaisAieuuuuuError:
            <span style="color: #808080; font-style: italic;"># faire un truc</span></pre></td></tr></table></div>

<p>A la première erreur, la boucle est interrompue définitivement. Par contre la condition <code>if machin</code> va continuer sa route.</p>
<p>Mais si vous faites :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">if</span> truc:
    <span style="color: #ff7700;font-weight:bold;">try</span>:
        <span style="color: #ff7700;font-weight:bold;">if</span> machin:
            <span style="color: #ff7700;font-weight:bold;">for</span> bidule <span style="color: #ff7700;font-weight:bold;">in</span> chose:
                <span style="color: #ff7700;font-weight:bold;">raise</span> MaisAieuuuuuError<span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Ca fait mal t'es con&quot;</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">except</span> MaisAieuuuuuError:
        <span style="color: #808080; font-style: italic;"># faire un truc</span></pre></td></tr></table></div>

<p>La condition <code>if machin</code> est définitivement interrompue.</p>
<p>Et si vous faites :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">try</span>:
    <span style="color: #ff7700;font-weight:bold;">if</span> truc:
        <span style="color: #ff7700;font-weight:bold;">if</span> machin:
            <span style="color: #ff7700;font-weight:bold;">for</span> bidule <span style="color: #ff7700;font-weight:bold;">in</span> chose:
                <span style="color: #ff7700;font-weight:bold;">raise</span> MaisAieuuuuuError<span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Ca fait mal t'es con&quot;</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">except</span> MaisAieuuuuuError:
    <span style="color: #808080; font-style: italic;"># faire un truc</span></pre></td></tr></table></div>

<p>Là, tout le programme est interrompu. Ca ne plantera pas, mais ça ne fera plus rien.</p>
<p>Il faut donc choisir soigneusement où attraper l&#8217;exception selon la partie du programme qu&#8217;on souhaite interrompre.</p>
<h2>Manipuler l&#8217;exception attrapée</h2>
<p>Les exceptions sont des objets complets. On peut les récupérer avec le mot clés <code>as</code> et analyser leur contenu.</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;">try</span>:
    f <span style="color: #66cc66;">=</span> <span style="color: #008000;">open</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;nawak&quot;</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">IOError</span> <span style="color: #ff7700;font-weight:bold;">as</span> e:
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;args: &quot;</span><span style="color: #66cc66;">,</span> e.<span style="color: black;">args</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;errno: &quot;</span><span style="color: #66cc66;">,</span> e.<span style="color: #dc143c;">errno</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;filename: &quot;</span><span style="color: #66cc66;">,</span> e.<span style="color: black;">filename</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;strerror: &quot;</span><span style="color: #66cc66;">,</span> e.<span style="color: black;">strerror</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;">## args:  (2, 'No such file or directory')</span>
<span style="color: #808080; font-style: italic;">## errno:  2</span>
<span style="color: #808080; font-style: italic;">## filename:  nawak</span>
<span style="color: #808080; font-style: italic;">## strerror:  No such file or directory</span></pre></td></tr></table></div>

<p>Il est même possible de les lever à nouveau après :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">try</span>:
    f <span style="color: #66cc66;">=</span> <span style="color: #008000;">open</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;nawak&quot;</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">IOError</span> <span style="color: #ff7700;font-weight:bold;">as</span> e:
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;args: &quot;</span><span style="color: #66cc66;">,</span> e.<span style="color: black;">args</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;errno: &quot;</span><span style="color: #66cc66;">,</span> e.<span style="color: #dc143c;">errno</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;filename: &quot;</span><span style="color: #66cc66;">,</span> e.<span style="color: black;">filename</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;strerror: &quot;</span><span style="color: #66cc66;">,</span> e.<span style="color: black;">strerror</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">raise</span> e</pre></td></tr></table></div>

<p><code>raise</code> appelé sans argument lève de toute façon automatiquement l&#8217;exception en cours. Mais il est possible de lever une autre exception :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">try</span>:
    f <span style="color: #66cc66;">=</span> <span style="color: #008000;">open</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;nawak&quot;</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">IOError</span> <span style="color: #ff7700;font-weight:bold;">as</span> e:
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;args: &quot;</span><span style="color: #66cc66;">,</span> e.<span style="color: black;">args</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;errno: &quot;</span><span style="color: #66cc66;">,</span> e.<span style="color: #dc143c;">errno</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;filename: &quot;</span><span style="color: #66cc66;">,</span> e.<span style="color: black;">filename</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;strerror: &quot;</span><span style="color: #66cc66;">,</span> e.<span style="color: black;">strerror</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">raise</span> MonError<span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;T'as encore oublie ton classeur Man&quot;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<h2>Erreur à la sortie de l&#8217;interpréteur</h2>
<p>Il est possible d&#8217;attraper n&#8217;importe quelle exception non gérée juste avant qu&#8217;elle fasse crasher le programme, sans avoir à mettre tout son code dans un gros <code>try/except</code>.</p>
<p>Il faut définir une fonction qui accepte 3 arguments que sont la classe de l&#8217;exception, l&#8217;instance de l&#8217;exception et l&#8217;objet traceback :</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> attrapez_les_tous<span style="color: black;">&#40;</span><span style="color: #008000;">type</span><span style="color: #66cc66;">,</span> value<span style="color: #66cc66;">,</span> <span style="color: #dc143c;">traceback</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;Pokemon !&quot;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Ensuite il faut l&#8217;attacher au module <code>sys</code> avec le bon nom :</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;">sys</span>
<span style="color: #dc143c;">sys</span>.<span style="color: black;">excepthook</span> <span style="color: #66cc66;">=</span> attrapez_les_tous</pre></td></tr></table></div>

<p>Et hop :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff4500;">1</span> / <span style="color: #ff4500;">0</span>
Pokemon <span style="color: #66cc66;">!</span></pre></td></tr></table></div>

<p>Alors, c&#8217;est certain que si vous faites ça, vous avez intérêt à savoir ce que vous branlez car vous pouver tuer le debuggage. Ou alors créer un super moyen de logger toute erreur sur un process séparé qui vous le présente dans une belle interface Web. Au choix.</p>
<h2>Les exceptions en dehors des erreurs</h2>
<p>Les exceptions sont la pour gérer des cas exceptionnels, et pas forcément une erreur. Par exemple, la boucle <code>for</code> utilise les exceptions pour savoir quand s&#8217;arrêter. En effet elle attend que l&#8217;itérateur qu&#8217;elle utilise lève <code>StopIteration</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> iterateur <span style="color: #66cc66;">=</span> <span style="color: #008000;">iter</span><span style="color: black;">&#40;</span><span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">3</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> next<span style="color: black;">&#40;</span>iterateur<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>iterateur<span style="color: black;">&#41;</span>
<span style="color: #ff4500;">1</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> next<span style="color: black;">&#40;</span>iterateur<span style="color: black;">&#41;</span>
<span style="color: #ff4500;">2</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> next<span style="color: black;">&#40;</span>iterateur<span style="color: black;">&#41;</span>
---------------------------------------------------------------------------
<span style="color: #008000;">StopIteration</span>                             Traceback <span style="color: black;">&#40;</span>most recent call last<span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&lt;</span>ipython-input-<span style="color: #ff4500;">11</span>-d90e1e04a685<span style="color: #66cc66;">&gt;</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: black;">&#40;</span><span style="color: black;">&#41;</span>
----<span style="color: #66cc66;">&gt;</span> <span style="color: #ff4500;">1</span> next<span style="color: black;">&#40;</span>iterateur<span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #008000;">StopIteration</span>:</pre></td></tr></table></div>

<p>Donc quand on fait ç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;">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;">3</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></pre></td></tr></table></div>

<p>En fait, la boucle fait un truc comme ça :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">iterateur <span style="color: #66cc66;">=</span> <span style="color: #008000;">iter</span><span style="color: black;">&#40;</span><span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">3</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">while</span> <span style="color: #008000;">True</span>:
    <span style="color: #ff7700;font-weight:bold;">try</span>:
        <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>next<span style="color: black;">&#40;</span>iterateur<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">StopIteration</span>:
        <span style="color: #ff7700;font-weight:bold;">break</span></pre></td></tr></table></div>

<p>Les exceptions en Python, c&#8217;est une grande histoire d&#8217;amour.</p>


feed_id: http://sametmax.com/?p=15766
title: Le don du mois : Mozilla 9
uri: Le-don-du-mois-Mozilla-7-Recently-updated
url: http://sametmax.com/le-don-du-mois-mozilla/
content:
<p>Régulièrement, je donne à des organismes. Je ne pense pas qu&#8217;il y ait un combat plus important que d&#8217;autres. Si une personne veut supporter les yorkshires dépressifs anorexiques, une autre les goths hémophiles sidaïques et une dernière les ti nenfants qui meurent de la faim mortelle dans le monde mondial, très bien.</p>
<p>Personnellement, j&#8217;ai tendance à donner à des entités qui ont produit un travail concret dont j&#8217;ai pu profiter des fruits dans ma vie. Je suis un égoïste. Typiquement : la quadrature du Net, VLC, Ubuntu, Libre Office, Debian, la Python et la Free Software Fondation, Wikipedia, etc.</p>
<p>Mais comment motiver les gens à donner ? </p>
<p>Ça c&#8217;est plus compliqué. Tous les bloggers le savent, nos liens en bas qui demandent la charité rapportent peau de balle. En deux ans, on a récolté 200 euros avec flatr et 0.x bitcoins.</p>
<p>Du coup je me suis dit que peut être en donnant l&#8217;exemple on allait créer des vocations. Voilà donc l&#8217;idée : à chaque fois que je vais donner des sous, je vais écrire un article pour dire à qui, combien, et pourquoi.</p>
<p>Le but est multiple :</p>
<ul>
<li>Faire une piqûre de rappel régulière. Moi-même, j&#8217;oublie de donner, et je n&#8217;ai pas l&#8217;intention de faire des dons mensuels automatiques.</li>
<li>Faire déculpabiliser les gens sur la somme ou la cible. Il n&#8217;y a pas de petite action. Si vous donnez 1 euro, une seule fois à <a href="http://www.fdn.fr/">FDN</a>, et plus jamais, personne va venir vous engueuler. </li>
<li>Faire parler un peu de l&#8217;organisme qui en bénéficie. Peut être que les lecteurs donneront un peu à eux également.</li>
</ul>
<h2>Et le gagnant du jour est Momo</h2>
<p>Mozilla, la boîte qui a fait Firefox, est vraiment, mais alors vraiment formidable.</p>
<p>Ce sont les premiers à avoir fournit un logiciel libre de qualité pour surfer le Web. Souvenez-vous : d&#8217;abord il s&#8217;appelait Pheonix, puis Firebird, avant de devenir Firefox, mais il est là depuis 13 ans ! S&#8217;inspirant du très beau Opera, il a proposé des fonctionnalités qui paraissent évidentes aujourd&#8217;hui comme les onglets, le blocage de pop up ou la complétion des champs de formulaires. Et surtout, <strong> il a popularisé le principe des extensions.</strong></p>
<p>Firefox, et donc Mozilla, est la raison pour laquelle vous pouvez profiter de pages sans pub grâce à <a href="http://en.wikipedia.org/wiki/Adblock_Plus">Adblock</a> aujourd&#8217;hui.</p>
<p>Firefox est la seule raison pour laquelle on s&#8217;est pas bouffé de l&#8217;IE pendant toutes ses années, Firefox est celui qui a montré la voie à l&#8217;équipe de Google pour qu&#8217;ils lancent Chrome, et la bataille sur les perfs d&#8217;affichage et d&#8217;exécution JS dont on bénéficie aujourd&#8217;hui.</p>
<p>Mais Mozilla, ce n&#8217;est pas que Firefox.</p>
<p>C&#8217;est une association à but non lucratif qui passe son temps à défendre le Web ouvert. En se battant sur les <a href="https://wiki.mozilla.org/Standards">standards</a>, en <a href="https://developer.mozilla.org/fr/">documentant</a> et en continuant de prendre des risques dans une industrie de plus en plus conservatrice.</p>
<p>En effet, malgré des revenus très inférieurs à la plupart des acteurs concurrents, Mozilla s&#8217;est lancé dans :</p>
<ul>
<li>La création d&#8217;un <a href="https://www.mozilla.org/en-US/firefox/os/">OS pour téléphone</a> entièrement libre et basés sur les technologies du Web. Sans Bidule store qui enferme les utilisateurs et développeur.</li>
<li>L&#8217;ajout de la VOIP (pensez skype) <a href="https://support.mozilla.org/en-US/kb/firefox-hello-video-and-voice-conversations-online">directement dans Firefox</a>, sans aucune inscription.</li>
<li>L&#8217;ajout d&#8217;une fonctionnalité de <a href="https://activations.cdn.mozilla.net/fr/">partage générique des liens.</a></li>
<li><a href="http://popcornjs.org/">Popcorn.js</a>, une lib pour augmenter l&#8217;interaction avec les videos HTML5.</li>
<li><a href="https://mozillalabs.com/en-US/pdfjs/">PFD.js</a>, une lib pour faire un rendu d&#8217;un PDF en pure JS.</li>
<li><a href="https://mozillalabs.com/en-US/togetherjs/">TogetherJS</a>, une lib pour faciliter le travail collaboratif sur une page.</li>
<li><a href="http://circus.readthedocs.org/en/0.11.1/">Circus</a>, un gestionnaire de processus clusterisable.</li>
</ul>
<p>Leurs projets libres sont <a href="https://github.com/mozilla">nombreux</a>, et il y en a plein en Python.</p>
<p>Mozilla est aussi le seul acteur à ne pas censurer son store pour répondre à ses besoins mercantiles. </p>
<p>Et les gars sont très approchables. Vous pouvez littéralement envoyer un tweet à Tarek Ziadé ou Tristan Nitot et avoir une réponse.</p>
<h2>Le don</h2>
<p>Il se trouve que Mozilla accepte les bitcoins sur <a href="https://sendto.mozilla.org/page/contribute/givenow-seq?source=base_url#page-1">sa page de don</a> \o/. Ils utilisent <a href="https://www.coinbase.com">Coinbase</a> comme plateforme, ce qui leur permet de hooker un mail de confirmation et d&#8217;avoir un retour sur paiement très rapide puisque Coinbase est initialement un service d&#8217;analyse de la block chain et qu&#8217;ils la surveillent en permanence.</p>
<p>J&#8217;ai donc fait un envoi de 0.25 BTC, ce qui équivalait à environ $50. Encore une fois, la somme est directement liée à ce que j&#8217;ai pu me permettre ce jour là. Si vous avez juste un euro à donner une fois dans l&#8217;année, c&#8217;est parfait. On s&#8217;en branle. Il y a des mois où je ne donne rien car j&#8217;ai pas un rond.</p>


feed_id: http://sametmax.com/?p=15764
title: Changement des points sur IndexError 18
uri: Changement-des-points-sur-IndexError-14-Recently-updated
url: http://sametmax.com/changement-des-points-sur-indexerror/
content:
<p>Juste pour signaler rapidement qu&#8217;on a changé la logique d&#8217;attribution de points sur indexerror.net.</p>
<p>Le réglage par défaut du site était de multiplier tous les gains de points par 10, ce qui incite les premiers utilisateurs car on a l&#8217;impression de progresser très vite.</p>
<p>Mais ça implique aussi que les points n&#8217;ont vite plus de sens : en 2 semaines j&#8217;avais cumulé plusieurs milliers de points.</p>
<p>Donc on a changé ça, et les points ont été recalculé pour que chacun ait un total plus raisonnable.</p>
<p>C&#8217;est donc tout à fait normal si vous les voyez chuter d&#8217;un coup. Max a envoyé un mail à tous les inscrits normalement, mais je mets la justification ici just in case.</p>


feed_id: http://sametmax.com/?p=15749
title: Comment utiliser IndexError ? 10
uri: Comment-utiliser-IndexError-3-Recently-updated
url: http://sametmax.com/comment-utiliser-indexerror/
content:
<p>Après un peu de rodage, <a href="http://indexerror.net">IndexError</a> est sur les rails : design amélioré, meilleur perfs, workflow plus clair, etc.</p>
<p>Néanmoins on a été très surpris avec Max : la plupart des utilisateurs n&#8217;ont aucune idée de comment on s&#8217;en sert.</p>
<p>Pourtant c&#8217;est un clone de <a href="http://stackoverflow.com">Stackoverflow</a>, un site tellement célèbre qu&#8217;il est dans la première page des résultats de Google pour toutes les recherches techniques.</p>
<p>Pourtant c&#8217;est un simple site de question/réponse.</p>
<p>Pourtant on passe régulièrement dans les commentaires pour expliquer le principe.</p>
<p>Malgré ça, les gens se mélangent les pinceaux, ou ont peur de mal faire, ou ne savent trop par où commencer. </p>
<p>Cela prouve une fois de plus ce que j&#8217;<a href="http://sametmax.com/bien-expliquer-quelque-chose-les-regles-de-base/">arrête</a> pas de <a hre"http://sametmax.com/il-ne-faut-pas-prendre-des-gens-pour-des-cons-mais-ne-jamais-oublier-quils-en-sont/>répéter</a> : l&#8217;évidence n&#8217;existe pas.</p>
<h2>A quoi sert IndexError ?</h2>
<p>A obtenir une réponse à sa question sur Python et son écosystème. C&#8217;est tout.</p>
<p>Pas à lancer un débat. Pas à discuter ou socialiser.</p>
<p>Le but est très simple : rendre service à celui qui pose la question maintenant mais aussi <strong>à ceux qui se la poseront dans le future.</strong></p>
<p>Sur le site, ça se traduit par avoir pour chaque question une page avec :</p>
<pre>[Titre de la question en gros]

| Détails de la question pour
| mieux comprendre le contexte

[Solution la plus probable]

[Solution un peu moins probable]

[Solution encore un peu moins probable]

[Solution encore un peu moins probable]

[Solution encore un peu moins probable]

Etc.</pre>
<h2>Comment on obtient ce résultat ?</h2>
<p>D&#8217;abord en virant tout l&#8217;enrobage. Pas de &#8220;bonjour&#8221;, &#8220;merci&#8221;, &#8220;je suis débutant&#8221;, etc. On pose la question, on donne une réponse.</p>
<p>Ensuite, en ne se souciant pas d&#8217;avoir tort. </p>
<p>Si vous pensez qu&#8217;une question est stupide, vous pouvez la poser.</p>
<p>Si vous n&#8217;êtes pas certain que votre réponse est la bonne, vous pouvez la donner.</p>
<p>Si vous pensez que la réponse est sur Google, vous pouvez la poser.</p>
<p>Pour citer un commentaire célèbre sur Stackoverflow : </p>
<blockquote><p>Chercher sur ce site plutôt que Google, c&#8217;est comme fait un accès hashmap plutôt que de parcourir une linked list.</p></blockquote>
<p>C&#8217;est le but : avoir toutes les questions possibles, et les réponses possibles à cette question.</p>
<p>En clair, si quelqu&#8217;un vous dis que votre question est conne ou vous dis de chercher sur Google dans un commentaire sur IndexError, vous pouvez l&#8217;envoyer se faire foutre.</p>
<p>IndexError est là pour faire gagner du temps. Être efficace. Résoudre des problèmes.</p>
<p>Ça ne vous dispense pas de rechercher si la question n&#8217;a pas déjà été posée sur le site avant de la poser, bien entendu.</p>
<h2>Commentaire VS Réponse</h2>
<p>Il y a beaucoup de confusion sur quand commenter, et quand répondre.</p>
<p><strong>Si vous êtes l&#8217;auteur de la question, vous voudrez presque toujours commenter.</strong> Il est très rare de répondre à sa propre question. C&#8217;est possible, et même encouragé si vous avez trouvé la réponse, mais c&#8217;est rare.</p>
<p>Si vous n&#8217;êtes pas l&#8217;auteur de la question :</p>
<ul>
<li>Toute demande d&#8217;informations supplémentaires ou remarque va en commentaire.</li>
<li>Toute solution possible va dans une réponse.</li>
</ul>
<p>Ex :</p>
<p><em>Il va falloir que tu nous poste ton fichier de config.</em> => commentaire.</p>
<p><em>Remplace True par False pour voir ce que ça fait</em> => réponse.</p>
<p>Et c&#8217;est la l&#8217;astuce : <strong>vous n&#8217;avez pas besoin d&#8217;être certain que votre réponse est la bonne</strong> pour la poster.</p>
<p>Les votes sont faits pour ça.</p>
<p>Postez toutes les solutions qui vous viennent en tête comme réponse, pas comme commentaire.</p>
<p>Si ce n&#8217;est pas la solution appropriée, la bonne sera votée,  montera dans le classement et passera devant la votre donc ce n&#8217;est pas grave. Mais plus tard, un mec peut passer, chercher la réponse à la question, et voir que VOTRE réponse est SA solution.</p>
<h2>Votez</h2>
<p>Pour que ça marche, il faut donc voter. Si une question est pertinente, votez la. Si une réponse est pertinente, votez la. Même si vous n&#8217;êtes pas l&#8217;auteur de la question. Voter fait parti intégrante de la participation au site.</p>
<p>La plupart du temps, on upvote, les quelques raisons possibles de downvote :</p>
<ul>
<li>La réponse est hors sujet, incompréhensible ou un spam.</li>
<li>La réponse est rédigée par un connard agressif.</li>
<li>Vous pensez que la réponse apporte plus de problèmes qu&#8217;elle n&#8217;en résout. Dans ce cas, signalez le downvote et justifiez le en commentaire.</li>
</ul>
<p><strong>Tout vote est annulable, donc n&#8217;ayez pas peur.</strong></p>
<p>De même, si une réponse est la solution à votre question, cliquez sur le symbole  	&#10003; à gauche de la réponse pour l&#8217;accepter. Ceci la propulse tout en haut de la liste des réponses, et change son style pour qu&#8217;elle soit plus visible. </p>
<p>En prime, toutes ces actions donnent des points, et les points sont importants, ce ne sont pas de simples gommettes pour gonfler l&#8217;égo des enfants de maternelle.</p>
<h2>Les points</h2>
<p>Ils servent à 2 choses.</p>
<p>D&#8217;une part, à permettre d&#8217;identifier les participants du site selon leur réputation. Si un réponse ou un commentaire est fait par quelqu&#8217;un de haute réputation, on peut se dire qu&#8217;on va y prêter plus d&#8217;attention qu&#8217;aux autres. C&#8217;est un gain de temps.</p>
<p>Mais surtout, les points sont attachées à des permissions.</p>
<p>En effet, sur IndexError, une autre personne peut éditer VOS questions et commentaires, comme sur un wiki. Le droit de faire cela ou non est lié au nombre de points qu&#8217;il a.</p>
<p>Voter donne des points. Poser des questions donne des points. Donner des réponses donne des points. Accepter des réponses donne des points.</p>


feed_id: http://sametmax.com/?p=15806
title: Twisted et requests 8
uri: Twisted-et-requests-4
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
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-1
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-2
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=15915
title: Je sais, je vous ai manqué 10
uri: Je-sais-je-vous-ai-manqué-1
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=15951
title: Le don du mois : VLC 6
uri: Le-don-du-mois-VLC
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-7-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=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=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=15993
title: Views VS generators 6
uri: Views-VS-generators-6
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=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-4-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=16039
title: Reformater son code avec yapf 16
uri: Reformater-son-code-avec-yapf-4
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=16027
title: Revue de code publique 17
uri: Revue-de-code-publique-12-Recently-updated
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=16045
title: Python 2 VS Python 3 : réalité de terrain 11
uri: Python-2-VS-Python-3-réalité-de-terrain-6-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 8
uri: Lancer-pdb-dès-qu-une-exception-a-lieu-4
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-4
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-8-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-6-Recently-updated
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>


