# articles

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

    Ok, c'est la merde internationale

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

    Je commence à merder

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

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

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

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

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

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

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

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

    Ok, c'est la merde internationale

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

    Je commence à merder

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

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

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

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


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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


feed_id: http://sametmax.com/?p=11299
title: Little things
uri: Little-things
url: http://sametmax.com/little-things/
content:
<div style="font-size:0.75em">
Terminer un stylo bic ou une gomme.</p>
<p>Éclater du papier bulle. Dont quelqu&#8217;un a besoin.</p>
<p>Passer une porte en train de se fermer sans la toucher.</p>
<p>Connecter un périphérique USB dans le bon sens d&#8217;un seul coup.</p>
<p>Vider une bouteille et remplir pile poil un verre avec. Ni trop, ni pas assez.</p>
<p>Marcher uniquement sur les bandes blanches du passage clouté sans changer de rythme.</p>
<p>Avoir un ascenseur qui s&#8217;ouvre et se ferme exactement calqué sur la basse du morceau qu&#8217;on écoute.</p>
<p>Coder un snippet d&#8217;une traite, sans regarder la doc, et l&#8217;exécuter pour voir que ça marche exactement comme prévu.</p>
<p>Mais dans notre métier, rien ne bat le sentiment jubilatoire de gagner 5 secondes en utilisant les raccourcis de son éditeur.
</p></div>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=11299&amp;md5=498e71292819dbe56a37b19309e2d2d1" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


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


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


feed_id: http://sametmax.com/?p=11331
title: Oblitérer un fichier de l’historique Git
uri: Oblitérer-un-fichier-de-l-historique-Git
url: http://sametmax.com/obliterer-un-fichier-de-lhistorique-git/
content:
<p>Si vous avez commité votre clé privée dans un repo, il existe un moyen de la dégommer de l&#8217;historique.</p>
<p><strong>ATTENTION, CECI EST UNE OPERATION DANGEREUSE.</strong></p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">git</span> filter-branch <span style="color: #660033;">-f</span> <span style="color: #660033;">--index-filter</span> <span style="color: #ff0000;">&quot;git rm -r --cached --ignore-unmatch chemin/vers/fichier&quot;</span> <span style="color: #660033;">--prune-empty</span> <span style="color: #660033;">--tag-name-filter</span> <span style="color: #c20cb9; font-weight: bold;">cat</span> <span style="color: #660033;">--</span> <span style="color: #660033;">--all</span></pre></div></div>

<p>Si le fichier a été dans plusieurs endroits durant sa vie, il faut relancer la commande pour chaque chemin.</p>
<p>Puis :</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">git</span> push remote branch <span style="color: #660033;">--force</span></pre></div></div>

<p>Cette seconde commande est à lancer pour chaque branche et chaque tag concerné.</p>
<p>Comme tout ce qui change l&#8217;historique, il faut que tous les autres repos appliquent aussi cette opération.</p>
<p>Tous vos collègues devront, soit appliquer eux aussi &#8220;filter-branch&#8221;, soit faire un rebase de toutes les branches basées sur celles modifiées par vous.</p>
<p>La commande peut prendre pas mal de temps à tourner. L&#8217;opération totale avec syncro entre collègues, je ne vous en parle pas. Et si vous foirez une étape, je vous garantis que ça va être la merde.</p>
<p>Mais c&#8217;est possible, en cas d&#8217;extrême urgence.</p>
<p>Pour se simplifier la tâche, il existe un <a href="http://rtyley.github.io/bfg-repo-cleaner/">petit soft</a> spécialisé pour ça qui est bien plus rapide et avec moins de risques.</p>
<p>Mais <a href="media/57b77245.obliterate.jpg" data-original-source="http://www.magiccorporation.com/scan/8th_edition/obliterate.jpg">ça reste dangereux</a>, donc mollo.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=11331&amp;md5=b44b41c39a343917fc84b1a89b46e92e" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=11340
title: Quel niveau peut-on exiger à l’embauche en Python ?
uri: Quel-niveau-peut-on-exiger-à-l-embauche-en-Python
url: http://sametmax.com/quel-niveau-peut-on-exiger-a-lembauche-en-python/
content:
<p>J&#8217;ai répondu récemment à une question sur le niveau qu&#8217;on pouvait attendre d&#8217;un professionnel en Python. La réponse était en anglais, alors je me fends d&#8217;une petite traduction ici.</p>
<blockquote><p>
Cela dépend beaucoup du niveau Python dont la boîte a besoin, et s&#8217;ils accordent plus d&#8217;importance à celui-ci ou à ta capacité générale à résoudre des problèmes et tes connaissances générales informatiques.</p>
<p>Pour répondre à ta question, je vais ignorer ces deux points puisqu&#8217;ils ne sont pas particulièrement liés à Python. Il y a plein d&#8217;articles de blog sur ces sujets sur le Web.</p>
<p>En Python, un dev standard devrait :</p>
<ul>
<li>être capable d&#8217;écrire du code Pythonique (style idiomatique, syntaxe PEP8&#8230;).</li>
<li>connaître la stdlib et l&#8217;écosystème de Python. Par exemple n&#8217;avoir aucun problème avec pip, virtualenv, datetime, os.path, hashlib, uuid, csv, pdb, json, et toutes les collections y compris celles qu&#8217;il y a dans le module éponyme ou les sets.</li>
<li>connaître les bases de la POO. L&#8217;héritage, l&#8217;overloading, les propriétés, la composition, etc.</li>
</ul>
<p>Un développeur Python avancé devrait être capable d&#8217;écrire des libs agréables, et donc :</p>
<ul>
<li>être à l&#8217;aise avec les générateurs et yield.</li>
<li>pouvoir écrire son propre décorateur.</li>
<li>pouvoir écrire son propre context manager.</li>
<li>pouvoir écrire son propre descripteur.</li>
<li>savoir gérer l&#8217;héritage multiple, l&#8217;injection de dépendance, etc.</li>
<li>pouvoir faire une lib de A à Z, incluant un API flexible et extensible, le packaging et la documentation.</li>
<li>savoir mettre en place des tests unitaires.</li>
</ul>
<p>Un expert Python devrait :</p>
<ul>
<li>connaître la plupart des libs tierces parties et frameworks pour la plupart des tâches, leurs qualités et leurs défauts.</li>
<li>pouvoir créer sa propre métaclasse.</li>
<li>être à l&#8217;aise avec l&#8217;introspection.</li>
<li>savoir contourner la plupart des faiblesses de Python : le GIL, les API bloquantes, créer soit-même un code non bloquant, créer un code compatible V2 et V3, etc.</li>
<li>être capable de prendre un projet sans doc, lire le code source, trouver son problème, et le résoudre via monkey patch tout en proposant un patch propre upstream.</li>
<li>savoir utiliser des modules difficiles ou peu connus comme heapq, inspect, nmap, etc.</li>
</ul>
<p>Selon ton domaine, tu auras également peut-être besoin d&#8217;être capable :</p>
<ul>
<li>de gérer plusieurs implémentations de Python.</li>
<li>d&#8217;écrire une extension C.</li>
<li>de maîtriser des libs spécifiques comme numpy, scrapy, opencv, etc.</li>
</ul>
</blockquote>
<p>Vous noterez que je n&#8217;ai pas mis des évidences comme savoir faire une fonction ou une boucle for. Évidemment qu&#8217;il faut savoir écrire du code basique sinon on ne sert à rien.</p>
<p>Gardez aussi en tête que chaque entreprise est différente, et donc peut avoir des besoins qui se situent n&#8217;importe où dans l&#8217;échelle ci-dessus.</p>
<p>Mais surtout, les connaissances dans un langage, bien qu&#8217;importantes, ne sont pas la priorité. Un langage, ça s&#8217;apprend. Être une personne qui résout les problèmes, communique, travaille bien en équipe et satisfait les clients, c&#8217;est plus difficile à former. </p>
<p>Par ailleurs, il n&#8217;existe pas de job avec juste du Python. Un dev backend devrait sans doute aussi travailler avec une base de données, faire du sys admin ou du réseau. Un dev d&#8217;UI devra gérer des problématiques multi-plateformes, de l&#8217;ergonomie, du packaging avancé. Un dev scientifique devra peut-être écrire du C ou du Fortran. Un dev Web est tenu de gérer le JS/CSS/HTML. Et il y a aussi les outils autour : bug tracking, versioning, peer review, etc.</p>
<p>Bref, dire seulement &#8220;je suis bon en Python&#8221; ne suffit pas à convaincre quelqu&#8217;un qu&#8217;il doit vous embaucher.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=11340&amp;md5=154a303a3def2a88220493964e57fc9f" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=11371
title: La télé crève et veut emporter Internet dans la tombe
uri: La-télé-crève-et-veut-emporter-Internet-dans-la-tombe
url: http://sametmax.com/la-tele-creve-et-veut-emporter-internet-dans-la-tombe/
content:
<p>Ça parle ici et là de &#8216;la neutralité du net&#8217; et franchement beaucoup de gens n&#8217;en ont rien à foutre. </p>
<p>Admettons.</p>
<p>Mais la question n&#8217;a pas besoin d&#8217;être prise de tête.</p>
<p>Les boites qui fournissent l&#8217;accès à Internet veulent faire payer plus les services qui &#8220;consomment&#8221; le plus. Ils décorent ça en disant qu&#8217;ils veulent donner un accès &#8220;prioritaire&#8221; ou &#8220;plus rapide&#8221; à ceux qui paieront plus.</p>
<div id="attachment_11375" class="wp-caption aligncenter" style="width: 521px"><a href="media/c24e6bc4.vision_csa.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/07/vision_csa.png"><img src="media/c24e6bc4.vision_csa.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/07/vision_csa.png" alt="Schéma montrant que Youtube a un gros trafic" title="Ce qu&#039;on essaye de faire gober aux gens" width="511" height="331" class="size-full wp-image-11375" /></a><p class="wp-caption-text">Ce qu&#039;on essaye de faire gober aux gens</p></div>
<p>Mais il y a une arnaque.</p>
<p><strong>CE NE SONT PAS LES SERVICES QUI CONSOMMENT INTERNET</strong></p>
<p>C&#8217;est vous.</p>
<p>Et vous payez déjà un abonnement qu&#8217;on vous a vendu comme illimité. Ce que vous faites de cet abonnement n&#8217;est pas le problème de ces boîtes. Que vous passiez votre temps sur youtube, facebook, LOL, wikipedia, IRC ou sametmax, c&#8217;est pareil.</p>
<p>Vous utilisez le débit maximum pour lequel vous payez, et l&#8217;accumulation de tous ces abos paie pour le trafic utilisé. Si beaucoup utilisent youtube, il y a plus de trafic vers youtube, mais il y a beaucoup d&#8217;abos payés de toute manière qui financent ce trafic.</p>
<div id="attachment_11376" class="wp-caption aligncenter" style="width: 520px"><a href="media/c8d3d745.vision_reelle.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/07/vision_reelle.png"><img src="media/c8d3d745.vision_reelle.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/07/vision_reelle.png" alt="D&#039;où vient le débit de youtube" title="La somme des débits est proportionelle à la somme des abonnements payés" width="510" height="344" class="size-full wp-image-11376" /></a><p class="wp-caption-text">La somme des débits est proportionelle à la somme des abonnements payés</p></div>
<p>Quand on envoie une lettre, on paie le prix du timbre en fonction du poids de sa lettre et de sa destination. Pas en fonction du nombre de lettres que le destinataire reçoit tous les jours. Parceque si il y a beaucoup de lettres, il y a beaucoup de timbres, donc c&#8217;est payé.</p>
<p>Bref, c&#8217;est une entube.</p>
<p>Une entube qui a été dernièrement défendue par le <a href="https://fr.wikipedia.org/wiki/Conseil_sup%C3%A9rieur_de_l%27audiovisuel_%28France%29">CSA</a>, organisme détestable s&#8217;il en est, mais que je croyais hors sujet. En fait pas du tout, la raison est très simple : la télévision est en train de crever, et <a href="http://www.ozap.com/actu/le-csa-veut-en-finir-avec-la-conception-absolutiste-de-la-neutralite-du-net/454146">ils essayent de ralentir l&#8217;agonie</a> en mettant des bâtons dans les roues de la concurrence en ligne.</p>
<p>Après l&#8217;industrie du disque, les grosses boîtes d&#8217;édition et la presse, c&#8217;est donc le dinaurorus télétus qui se rend compte qu&#8217;il est en voie d&#8217;extinction. Et comme tous les autres depuis 20 ans, au lieu de se remettre en question et sauver son cul, il s&#8217;accroche à ses rides et fait caca partout.</p>
<p>Bonne chance, maintenant qu&#8217;il y a des mobiles dans tous les foyers, pour bloquer la nouvelle génération devant un écran dans le salon à une heure précise. Avec tout le pognon qu&#8217;ils ont, la mort sera lente, et chiante pour tout le monde. J&#8217;espère néanmoins qu&#8217;elle se fera dans beaucoup de souffrances. Pour eux.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=11371&amp;md5=f2178bebd3dea5fd11ad45f86b28323d" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=11382
title: Chercher dans plusieurs dicts à la fois avec ChainMap
uri: Chercher-dans-plusieurs-dicts-à-la-fois-avec-ChainMap
url: http://sametmax.com/chercher-dans-plusieurs-dicts-a-la-fois-avec-chainmap/
content:
<p>Depuis Python 3.3 existe un nouvel outil pour travailler avec les dicos et j&#8217;étais complètement passé à côté : <a href="https://docs.python.org/3.3/library/collections.html#collections.ChainMap">ChainMap</a>.</p>
<p>Il permet de créer un objet qui se comporte comme un <a href="http://sametmax.com/aller-plus-loin-avec-les-hash-maps-en-python/">dict</a>, mais qui va chercher dans plusieurs dictionnaires.</p>
<p>Un exemple sera plus clair.</p>
<p>Imaginez que vous ayez un système de configuration avec des valeurs par défaut :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">default_config = <span style="color: black;">&#123;</span><span style="color: #483d8b;">'DEBUG'</span>: <span style="color: #008000;">False</span>, <span style="color: #483d8b;">'HOST'</span>: <span style="color: #483d8b;">'localhost'</span>, <span style="color: #483d8b;">'PORT'</span>: <span style="color: #ff4500;">8080</span><span style="color: black;">&#125;</span></pre></div></div>

<p>Puis votre utilisateur peut fournir un fichier de configuration <code>settings.py</code> qui contient :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">DEBUG = <span style="color: #008000;">True</span>
PORT = <span style="color: #ff4500;">8000</span></pre></div></div>

<p>Et avec un peu de parsing, vous le récupérez sous forme de dico :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> settings
user_config = <span style="color: black;">&#123;</span>k: v <span style="color: #ff7700;font-weight:bold;">for</span> k, v <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">vars</span><span style="color: black;">&#40;</span>settings<span style="color: black;">&#41;</span>.<span style="color: black;">items</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">if</span> k.<span style="color: black;">isupper</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#125;</span>
<span style="color: #808080; font-style: italic;">## {'DEBUG': True, 'PORT': 8000}</span></pre></div></div>

<p>Puis l&#8217;utilisateur peut passer la config via la ligne de commande, et une fois il fait :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">--host 0.0.0.0</pre></div></div>

<p>Et vous récupérez la config :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">cmd_config = <span style="color: black;">&#123;</span><span style="color: #483d8b;">&quot;HOST&quot;</span>: <span style="color: #483d8b;">&quot;0.0.0.0&quot;</span><span style="color: black;">&#125;</span></pre></div></div>

<p>Maintenant il faut prendre tout ça en compte. La ligne de commande écrase le fichier de config qui écrase les valeurs par défaut :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">conf = <span style="color: black;">&#123;</span><span style="color: black;">&#125;</span>
conf.<span style="color: black;">update</span><span style="color: black;">&#40;</span>default_config<span style="color: black;">&#41;</span>
conf.<span style="color: black;">update</span><span style="color: black;">&#40;</span>user_config<span style="color: black;">&#41;</span>
conf.<span style="color: black;">update</span><span style="color: black;">&#40;</span>cmd_config<span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>conf<span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># configuration finale</span>
<span style="color: #808080; font-style: italic;">## {'DEBUG': True, 'HOST': '0.0.0.0', 'PORT': 8000}</span></pre></div></div>

<p>Ça va marcher, mais ça a plusieurs défauts : </p>
<ul>
<li>Si vos dicos sont très grands, vous prenez encore plus de place en mémoire.</li>
<li>Si vous modifiez <code>conf</code>, impossible de savoir quelle était sa valeur initiale.</li>
<li>Si vous modifiez <code>user_config</code>, il faut tout refusionner. Mais si vous avez modifié <code>conf</code> entre temps, comment vous assurer que vous n&#8217;allez pas écraser ces modifications ?</li>
<li>Si vous voulez temporairement faire une modification à conf, il faut de nouveau créer un dico en plus avec tout dedans.</li>
</ul>
<p>ChainMap résout ce problème en cherchant une clé dans une liste de dicos sous-jacent, mais en appliquant les modifications uniquement sur le premier dico.</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">from</span> <span style="color: #dc143c;">collections</span> <span style="color: #ff7700;font-weight:bold;">import</span> ChainMap
&nbsp;
<span style="color: #66cc66;">&gt;&gt;&gt;</span> conf = ChainMap<span style="color: black;">&#40;</span><span style="color: black;">&#123;</span><span style="color: black;">&#125;</span>, <span style="color: #808080; font-style: italic;"># &lt;- ce mapping sera le seul modifié</span>
                    <span style="color: #808080; font-style: italic;"># les clés seront cherchées dans cet ordre :</span>
                    cmd_config, 
                    user_config, 
                    default_config<span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #66cc66;">&gt;&gt;&gt;</span> conf<span style="color: black;">&#91;</span><span style="color: #483d8b;">'HOST'</span><span style="color: black;">&#93;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #483d8b;">'0.0.0.0'</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> conf<span style="color: black;">&#91;</span><span style="color: #483d8b;">'DEBUG'</span><span style="color: black;">&#93;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #008000;">True</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> conf<span style="color: black;">&#91;</span><span style="color: #483d8b;">'PORT'</span><span style="color: black;">&#93;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff4500;">8000</span></pre></div></div>

<p>Les dicos sont ici stockés par référence, ça ne prend pas de mémoire en plus, et si on modifie un dico :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">user_config<span style="color: black;">&#91;</span><span style="color: #483d8b;">'DEBUG'</span><span style="color: black;">&#93;</span> = <span style="color: #008000;">False</span></pre></div></div>

<p>Alors c&#8217;est reflété par <code>ChainMap</code>:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> conf<span style="color: black;">&#91;</span><span style="color: #483d8b;">'DEBUG'</span><span style="color: black;">&#93;</span>
<span style="color: #008000;">False</span></pre></div></div>

<p>Si on fait une modification, seul le dico le plus haut dans la chaine (ici notre dico vide), est modifié :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> conf<span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;PORT&quot;</span><span style="color: black;">&#93;</span> = <span style="color: #ff4500;">7777</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> conf
<span style="color: #66cc66;">&gt;&gt;&gt;</span> ChainMap<span style="color: black;">&#40;</span><span style="color: black;">&#123;</span><span style="color: #483d8b;">'PORT'</span>: <span style="color: #ff4500;">7777</span><span style="color: black;">&#125;</span>, <span style="color: black;">&#123;</span><span style="color: #483d8b;">'HOST'</span>: <span style="color: #483d8b;">'0.0.0.0'</span><span style="color: black;">&#125;</span>, <span style="color: black;">&#123;</span><span style="color: #483d8b;">'DEBUG'</span>: <span style="color: #008000;">False</span>, <span style="color: #483d8b;">'PORT'</span>: <span style="color: #ff4500;">8000</span><span style="color: black;">&#125;</span>, <span style="color: black;">&#123;</span><span style="color: #483d8b;">'DEBUG'</span>: <span style="color: #008000;">False</span>, <span style="color: #483d8b;">'HOST'</span>: <span style="color: #483d8b;">'localhost'</span>, <span style="color: #483d8b;">'PORT'</span>: <span style="color: #ff4500;">8080</span><span style="color: black;">&#125;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Et si on a besoin d&#8217;un contexte temporaire, on peut créer un enfant :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> sub_conf = conf.<span style="color: black;">new_child</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> sub_conf
ChainMap<span style="color: black;">&#40;</span><span style="color: black;">&#123;</span><span style="color: black;">&#125;</span>, <span style="color: black;">&#123;</span><span style="color: #483d8b;">'PORT'</span>: <span style="color: #ff4500;">7777</span><span style="color: black;">&#125;</span>, <span style="color: black;">&#123;</span><span style="color: #483d8b;">'HOST'</span>: <span style="color: #483d8b;">'0.0.0.0'</span><span style="color: black;">&#125;</span>, <span style="color: black;">&#123;</span><span style="color: #483d8b;">'DEBUG'</span>: <span style="color: #008000;">False</span>, <span style="color: #483d8b;">'PORT'</span>: <span style="color: #ff4500;">8000</span><span style="color: black;">&#125;</span>, <span style="color: black;">&#123;</span><span style="color: #483d8b;">'DEBUG'</span>: <span style="color: #008000;">False</span>, <span style="color: #483d8b;">'HOST'</span>: <span style="color: #483d8b;">'localhost'</span>, <span style="color: #483d8b;">'PORT'</span>: <span style="color: #ff4500;">8080</span><span style="color: black;">&#125;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Cela crée un nouveau ChainMap, avec un dico vide en haut de la chaîne, qui permet donc de travailler temporairement avec de nouvelles valeurs, sans toucher au ChainMap d&#8217;origine. </p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=11382&amp;md5=fa50611641db31862af3526a3b023589" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=11399
title: Je passe
uri: Je-passe
url: http://sametmax.com/je-passe/
content:
<p>Pas envie d&#8217;écrire en ce moment, donc pause.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=11399&amp;md5=bf10027679584e71483fc9ecb2ce144e" title="Flattr" target="_blank"><img src="media/fc229d00.flattr-badge-large.png" data-original-source="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>


feed_id: http://sametmax.com/?p=11720
title: Recherche config pour relation sérieuse
uri: Recherche-config-pour-relation-sérieuse
url: http://sametmax.com/recherche-config-pour-relation-serieuse/
content:
<p>RIP ma machine, mais ne tenant pas m&#8217;enliser dans le veuvage, je cherche à me recaser rapidement avec un ultra portable de bonne compagnie.</p>
<p>Malheureusement, le <a href="http://www.samsung.com/my/consumer/pc-peripherals-printer/notebook-pc/ultra-portable/NP900X3C-A01MY">Samsung NP900X3C</a> que je souhaitais demander en mariage est impossible à trouver. Les dernières boutiques en ligne sur lesquelles je l&#8217;ai vu en stock étaient soient très mal vues sur les forums, soient incapables de poursuivre la commande jusqu&#8217;à son terme (novotech&#8230;). Je pense que c&#8217;est parce que le modèle commence à être un peu vieux, et maintenant en informatique, dès que c&#8217;est #old, on euthanasie.</p>
<p>J&#8217;ai trouvé un modèle pas mal chez keynux qui s&#8217;en rapproche, mais allez savoir, ils ne l&#8217;ont plus. Or il fait très beau, aussi j&#8217;aimerais profiter de mon été comme tout geek normal en restant devant mon ordi. A la fnac, ils m&#8217;ont conseillé d&#8217;attendre fin août, mais j&#8217;aurais des coups de soleil d&#8217;ici là.</p>
<p>Aussi, si vous connaissez une config similaire, faites le moi savoir :</p>
<ul>
<li>Format ultra portable, diag de 13 ou 14 pouces. Moins c&#8217;est inutilisable, plus c&#8217;est relou à transporter.</li>
<li>Ecran mat anti-reflet, très lumineux et non tactile pour usage confortable en extérieur. J&#8217;ai un hamac, faut le rentabiliser.</li>
<li>SSD 256go min car 23 virtualenv, 12 images dockers et dota en dual boot, ça prend de la place.</li>
<li>Pas de marque Sony, Compaq, Apple ou HP. Ils sont vilains.</li>
<li>Clavier et alimentation français car un clavier azerty en vaut deux.</li>
</ul>
<p>Préférablement connu pour fonctionner sous Linux et avec un son décent (de quoi écouter une vidéo en streaming sans grimacer). Une batterie avec 6h ou plus d&#8217;autonomie serait vraiment idéal mais je suis près à faire un compromis là dessus.</p>
<p>Je me branle du prix, du proc ou de la carte graphique. Je n&#8217;ai pas besoin de fonctionalités avancées ou de gadgets magiques. L&#8217;USB et le HDMI sont la seule connectique que j&#8217;utilise vraiment.</p>
<p>J&#8217;ai une bonne situation et fais très bien la cuisine. Merci.</p>


feed_id: http://sametmax.com/?p=11764
title: Ne pas faire d’enfant est-il égoïste ?
uri: Ne-pas-faire-d-enfant-est-il-égoïste
url: http://sametmax.com/ne-pas-faire-denfant-est-il-egoiste/
content:
<p>Je vais faire court car j&#8217;ai piscine!</p>
<p>On est dimanche matin, il fait beau dehors, les oiseaux gazouillent, un petit fond de musique des années 90.<br />
J&#8217;ai ma tasse de café &#8220;<a href="http://www.youtube.com/watch?v=cAehGOV7PFs">mon grain de saveur</a>&#8220;, je vérifie le chiffre d&#8217;affaire de mes sites internet, l&#8217;argent rentre, faudra peut-être investir ici après tout. J&#8217;habite en Asie depuis un an, il y a peu de mauvais et beaucoup de bon.</p>
<p>Dans un mois c&#8217;est la rentrée des classes en France, mes anciens amis sont quasiment tous en couple, avec 1 ou plusieurs enfants, certains sont déjà séparés avec gamins sur les bras, alternance des visites, etc. La routine quoi.</p>
<p><strong>On ne peut pas être partout.</strong></p>
<p>Moi je suis seul, je n&#8217;ai pas de femme, pas de gosse, pas de chien, même pas une petite mycose pour me tenir companie.<br />
Le pire c&#8217;est que j&#8217;aime ça, si je veux partir à Tokyo demain à quoi dois-je penser ?<br />
A qui vais-je demander la permission ? Personne.<br />
Quelles sont mes contraintes ? Aucune<br />
Quel est mon budget ? Très large.</p>
<p>Je suis le stéréotype du célibataire baroudeur, en couple 7 ans il y a plusieurs années de cela je pense avoir été vacciné, passé par toutes les étapes, de l&#8217;amour à la haine (dans l&#8217;ordre). Avec tous les clichés que l&#8217;on peut imaginer. Sans rien regretter au final.</p>
<p><strong>Le tournant:</strong></p>
<p>Seulement voilà, là où mes amis ont commencé à envisager de fonder une famille j&#8217;ai préféré investir dans ma vie professionnelle, de plus la crise était en route, la surpopulation me posait un problème de conscience. Ma vision de l&#8217;avenir se rapprochant <a href="http://www.youtube.com/watch?v=icmRCixQrx8">toujours plus de ça</a>.</p>
<p>Quelques années ont passé et j&#8217;ai vu mes amis &#8220;fonder&#8221; leur famille sur le si joli modèle que l&#8217;on nous vend, avec la télé 16:9 à crédit, la PS3 à crédit, l&#8217;iPhone à credit, le VolksWagen à crédit, le chien à crédit, bref une vie à crédit.<br />
Le boulot dont ils parlent avec dégoût, &#8220;mais c&#8217;est alimentaire tu comprends, ça va changer&#8221; n&#8217;est pas amusant pour eux.<br />
Les vacances ? &#8220;Je ne peux pas j&#8217;ai le crédit du nouveau VolksWagen que l&#8217;on vient d&#8217;acheter parce que tu comprends il a l&#8217;allume-cigare connecté à l&#8217;iPhone&#8221;. 35 000€, avec réduction de 5% sur le levier de vitesse en acajou véritable de Taiwan.</p>
<p>Certains s&#8217;en sortent mieux que d&#8217;autres quand même, soyons objectif.</p>
<p><strong>Au final ?</strong></p>
<p>Résulats des courses, ma mère me reproche d&#8217;être un égoïste car je n&#8217;ai pas fait d&#8217;enfant &#8220;comme tout le monde&#8221;, mes anciens amis me disent que j&#8217;ai de la chance mais qu&#8217;eux ne peuvent pas bouger à cause des enfants, des crédits, d&#8217;ailleurs c&#8217;est l&#8217;heure d&#8217;aller à Carrefour remplir le caddie.</p>
<p>Les enfants sont nécessaires à la survie de la race humaine, avoir des enfants est également un bonheur pour les parents, sans ça je ne serais pas là. Mais depuis 40 ans tout s&#8217;est accéléré.</p>
<p>&#8211; A l&#8217;heure où l&#8217;on soupçonne très fortement notre civilisation d&#8217;être <a href="http://www.lepoint.fr/sciences-nature/notre-civilisation-touche-a-sa-fin-assure-la-nasa-19-03-2014-1803180_1924.php">condamnée à court terme</a> du moins telle que nous la connaissons.</p>
<p>&#8211; Avec une démographie incontrôlable, déjà 7 Milliards.</p>
<figure id="attachment_11765" style="width: 440px;" class="wp-caption aligncenter"><img src="media/330ab466.440px-Population_curve.svg_.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/08/440px-Population_curve.svg_.png" alt="" title="population mondiale" width="440" height="260" class="size-full wp-image-11765" /><figcaption class="wp-caption-text">Et oui ça fait mal au fion...</figcaption></figure>
<p>&#8211; Avec des <a href="http://www.fukushima-blog.com/tag/au%20japon/">contaminations nucléaires pas anodines</a>.</p>
<p>&#8211; Avec une exploitation des ressources <a href="http://www.lemonde.fr/planete/article/2012/07/09/la-fracturation-hydraulique-poserait-un-risque-pour-les-sources-d-eau_1731413_3244.html">toujours plus intenses</a>. </p>
<p>Je me pose souvent cette question:</p>
<p>Est-ce-que je suis égoïste de ne pas vouloir d&#8217;enfant ou est-ce que ce sont ceux qui ont des enfants qui sont égoïstes alors que la planète ne peut pas les accueillir convenablement ?</p>
<p>Je n&#8217;ai pas de problème avec ma mère.</p>
<p>Et vous ?</p>
<p>PS: <em>Pour éviter le Fast-Trolling je précise que je ne suis pas contre la famille, bien au contraire, mais le mot famille n&#8217;a plus le même sens qu&#8217;il y a 40 ans il faut l&#8217;avouer. Avec un <a href="http://www.insee.fr/fr/themes/document.asp?ref_id=T10F032">divorce au bout de 5 ans</a> à la clef, des enfants à charge, c&#8217;est plus de la &#8220;consommation&#8221;.<br />
Si cela ne tenait qu&#8217;à moi je ferais faire des tests de QI à ceux qui veulent avoir des enfants. J&#8217;ai eu droit à l&#8217;étiquette d&#8217;eugéniste en herbe avec cette phrase&#8230;</em></p>
<p><iframe width="420" height="315" src="//www.youtube.com/embed/3uy_RstrLp4" frameborder="0" allowfullscreen></iframe></p>


feed_id: http://sametmax.com/?p=12078
title: Un gros guide bien gras sur les tests unitaires en Python, partie 3
uri: Un-gros-guide-bien-gras-sur-les-tests-unitaires-en-Python-partie-3
url: http://sametmax.com/un-gros-guide-bien-gras-sur-les-tests-unitaires-en-python-partie-3/
content:
<p>Pas mal de temps s&#8217;est écoulé depuis notre dernier article sur les tests. Ok, le dernier article Python tout court puisque je vous ai lâchement abandonnés pendant plus d&#8217;un mois. Je vous rassure, je n&#8217;ai pas du tout pensé à vous, je me suis bien amusé.</p>
<p>Mais je ne vous avais pas non plus oublié. J&#8217;étais juste parfaitement fainéant. C&#8217;est que ça demande du taff ces petites bêtes là.</p>
<p>Aujourd&#8217;hui, nous allons voir la même chose que la <a href="http://sametmax.com/un-gros-guide-bien-gras-sur-les-tests-unitaires-en-python-partie-2/">partie précédente</a>, mais avec une autre lib.</p>
<p>En effet, si vous voulez rester sains d&#8217;esprit et ne pas perdre votre motivation à rédiger des tests, utiliser le module unittest est une mauvaise idée. C&#8217;est verbeux, lourd, pas pratique. C&#8217;est caca.</p>
<p>Il existe bien mieux, et toutes les personnes que je connais qui sont sérieuses à propos des tests l&#8217;utilisent : <a href="http://pytest.org/latest/">PyTest</a>.</p>
<p>Et pour donner un petit goût de fiesta :</p>
<p><object width="420" height="315"><param name="movie" value="//www.youtube.com/v/l-qgum7hFXk?version=3&amp;hl=fr_FR&amp;rel=0"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="//www.youtube.com/v/l-qgum7hFXk?version=3&amp;hl=fr_FR&amp;rel=0" type="application/x-shockwave-flash" width="420" height="315" allowscriptaccess="always" allowfullscreen="true"></embed></object></p>
<h2>Principe</h2>
<p>Je vous en avais parlé ici, principe de pytest, c&#8217;est :</p>
<ul>
<li>De découvrir les tests automatiquement, et facilement.</li>
<li>D&#8217;écrire le moins de boiler plate possible.</li>
<li>D&#8217;avoir un style de test naturel.</li>
</ul>
<p>Ça s&#8217;installe avec pip :</p>
<pre lang="bash">pip install pytest</pre>
<p>Et en gros, au lieu de faire :</p>
<pre lang="python">import unittest

class TestBidule(unittest.TestCase):

    def test_machin(self):
        self.assertEqual(foo, bar)

if __name__ == '__main__':
    unittest.main()
</pre>
<p>On fait:</p>
<pre lang="python">def test_machin():
    assert foo == bar</pre>
<p>Yep, c&#8217;est tout. Même pas d&#8217;import. C&#8217;est beau non ?</p>
<p>Il y a beaucoup de magie pour que ça marche. D&#8217;abord, le lanceur de pytest détecte toutes les fonctions nommées <code>test_*</code> contenues dans des modules nommés également avec ce motif, et les lance comme un test. Ensuite, il analyse les <code>assert</code>, et devine ce que vous voulez faire avec, et fait le bon test qui va bien.</p>
<p>Ce genre d&#8217;opération est un des rares endroits où je tolère de la grosse magie en Python. En effet, les tests, c&#8217;est tellement relou que si on n&#8217;a pas un moyen ultra simple de les faire, on ne les fait pas.</p>
<h2>Traduction</h2>
<p>On va donc prendre les exemples qu&#8217;on a vus avec unittest, et les traduire dans leur équivalent pytest.</p>
<pre lang="python">import unittest

from mon_module import get

class TestFonctionGet(unittest.TestCase):

    def test_get_element(self):
        simple_comme_bonjour = ('pomme', 'banane')
        element = get(simple_comme_bonjour, 0)
        self.assertEqual(element, 'pomme')

    # Il faut choisir un nom explicite pour chaque méthode de test
    # car ça aide à débugger.
    def test_element_manquant(self):
        simple_comme_bonjour = ('pomme', 'banane')
        element = get(simple_comme_bonjour, 1000, 'Je laisse la main')
        self.assertEqual(element, 'Je laisse la main')


if __name__ == '__main__':
    unittest.main()</pre>
<p>Devient alors  :</p>
<pre lang="python">
from mon_module import get

def test_get():
    simple_comme_bonjour = ('pomme', 'banane')
    element = get(simple_comme_bonjour, 0)
    assert element == 'pomme'

def test_element_manquant():
    simple_comme_bonjour = ('pomme', 'banane')
    element = get(simple_comme_bonjour, 1000, 'Je laisse la main')
    assert element == 'Je laisse la main'
</pre>
<p>On lance la commande <code>py.test</code> (le point est important), sans spécifier de fichier :</p>
<pre lang="bash">$ py.test .
============================= test session starts ==============================
platform linux2 -- Python 2.7.6 -- py-1.4.23 -- pytest-2.6.1
collected 2 items

test_get.py ..</pre>
<p>Arf, j&#8217;ai lancé Python 2.7 au lieu du 3.4. Les vieilles habitudes ont la vie dure. Pas grave, c&#8217;est pareil avec les deux versions de Python.</p>
<p>Dans tous les cas, pytest va parcourir le dossier donné récursivement, et détecter tous les modules Python nommés <code>test_</code> puis extraire les tests qu&#8217;il contient. L&#8217;effort à fournir est minimal, et c&#8217;est ce qu&#8217;on lui demande.</p>
<h2>Les erreurs</h2>
<p>Vu qu&#8217;on n&#8217;utilise pas de méthode <code>assertChose</code>, on pourrait croire que les informations qu&#8217;on obtient en retour sont limitées. Que nenni, pytest fait beaucoup d&#8217;efforts pour extrapoler du sens depuis nos <code>assert</code> et va nous pondre un rapport tout à fait complet.</p>
<p>Prenons le cas :</p>
<pre lang="python">class TestFonctionGet(unittest.TestCase):

    def test_get_element(self):
        simple_comme_bonjour = ('pomme', 'banane')
        element = get(simple_comme_bonjour, 0)
        self.assertEqual(element, 'pomme')

    def test_element_manquant(self):
        simple_comme_bonjour = ('pomme', 'banane')
        element = get(simple_comme_bonjour, 1000, 'Je laisse la main')
        self.assertEqual(element, 'Je laisse la main')

    def test_avec_error(self):
        simple_comme_bonjour = ('pomme', 'banane')
        simple_comme_bonjour[1000]</pre>
<p>Qui donnait :</p>
<pre lang="bash">$ python test_get.py
E..
======================================================================
ERROR: test_avec_error (__main__.TestFonctionGet)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "test_get.py", line 40, in test_avec_error
    simple_comme_bonjour[1000]
IndexError: tuple index out of range

----------------------------------------------------------------------
Ran 3 tests in 0.001s

FAILED (errors=1)</pre>
<p>Avec pytest, le code est allégé :</p>
<pre lang="python">def test_get():
    simple_comme_bonjour = ('pomme', 'banane')
    element = get(simple_comme_bonjour, 0)
    assert element == 'pomme'

def test_element_manquant():
    simple_comme_bonjour = ('pomme', 'banane')
    element = get(simple_comme_bonjour, 1000, 'Je laisse la main')
    assert element == 'Je laisse la main'

def test_avec_error():
    simple_comme_bonjour = ('pomme', 'banane')
    simple_comme_bonjour[1000]</pre>
<p>Et la sortie est pourtant un peu plus lisible :</p>
<pre lang="bash">$ py.test
============================= test session starts ==============================
platform linux2 -- Python 2.7.6 -- py-1.4.23 -- pytest-2.6.1
collected 3 items

test_get.py ..F

=================================== FAILURES ===================================
_______________________________ test_avec_error ________________________________

    def test_avec_error():
        simple_comme_bonjour = ('pomme', 'banane')
>       simple_comme_bonjour[1000]
E       IndexError: tuple index out of range

test_get.py:22: IndexError</pre>
<p>Le plus intéressant est la manière dont sont gérées les erreurs logiques. Encore une fois l&#8217;exemple précédent :</p>
<pre lang="python">
class TestFonctionGet(unittest.TestCase):

    def test_get_element(self):
        simple_comme_bonjour = ('pomme', 'banane')
        element = get(simple_comme_bonjour, 0)
        self.assertEqual(element, 'pomme')

    def test_element_manquant(self):
        simple_comme_bonjour = ('pomme', 'banane')
        element = get(simple_comme_bonjour, 1000, 'Je laisse la main')
        self.assertEqual(element, 'Je laisse la main')

    def test_avec_echec(self):
        simple_comme_bonjour = ('pomme', 'banane')
        element = get(simple_comme_bonjour, 1000, 'Je laisse la main')
        self.assertEqual(element, 'Je tres clair, Luc')</pre>
<p>Et :</p>
<pre lang="bash">$ python test_get.py
F..
======================================================================
FAIL: test_avec_echec (__main__.TestFonctionGet)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "test_get.py", line 45, in test_avec_echec
    self.assertEqual(element, 'Je tres clair, Luc')
AssertionError: 'Je laisse la main' != 'Je tres clair, Luc'
- Je laisse la main
+ Je tres clair, Luc


----------------------------------------------------------------------
Ran 3 tests in 0.002s

FAILED (failures=1)</pre>
<p>Peut-on faire mieux ? Of course :</p>
<pre lang="python">def test_get():
    simple_comme_bonjour = ('pomme', 'banane')
    element = get(simple_comme_bonjour, 0)
    assert element == 'pomme'

def test_element_manquant():
    simple_comme_bonjour = ('pomme', 'banane')
    element = get(simple_comme_bonjour, 1000, 'Je laisse la main')
    assert element == 'Je laisse la main'


def test_avec_echec():
    simple_comme_bonjour = ('pomme', 'banane')
    element = get(simple_comme_bonjour, 1000, 'Je laisse la main')
    assert element == 'Je tres clair, Luc'
</pre>
<p>Et malgré cette concision, pytest est très prolixe dans sa sortie :</p>
<pre lang="bash">$ py.test
============================= test session starts ==============================
platform linux2 -- Python 2.7.6 -- py-1.4.23 -- pytest-2.6.1
collected 3 items

test_get.py ..F

=================================== FAILURES ===================================
_______________________________ test_avec_echec ________________________________

    def test_avec_echec():
        simple_comme_bonjour = ('pomme', 'banane')
        element = get(simple_comme_bonjour, 1000, 'Je laisse la main')
>       assert element == 'Je tres clair, Luc'
E       assert 'Je laisse la main' == 'Je tres clair, Luc'
E         - Je laisse la main
E         + Je tres clair, Luc

test_get.py:24: AssertionError</pre>
<p>Je m&#8217;arrête pour faire une pause &#8220;vis ma vie de Sam&#8221;. Je suis en train de rédiger cet article en face d&#8217;une caricature de hipster (j&#8217;écris beaucoup dans les transports) : la barbe de baroudeur en brousse, la coupe de cheveux de &#8220;Thrift shop&#8221; absolument immaculée, les lunettes de mamie, le Mac book tout neuf, le petit t-shirt discret mais branché, tout y est. Sauf que là, il vient de sortir un appareil <strong>à pellicule</strong> pour prendre une photo du paysage, et j&#8217;ai beaucoup de mal à me retenir de rire. Ce paragraphe me permet de maintenir une apparence civile. Putain je suis sûr que c&#8217;est du noir et blanc et qu&#8217;il les développe lui-même.</p>
<p>Fin de la parenthèse.</p>
<p>Contrairement à unittest, pytest n&#8217;a pas besoin d&#8217;une floppée de méthodes <code>assert*</code>, et il comprend parfaitement les idiomes Python :</p>
<pre>assertDictEqual => assert a == b
assertFalse => assert not a
assertGreater => assert a > b
assertIn => assert a in b
assertIs => assert a is b</pre>
<p>Etc.</p>
<h2>Setup et TearDown à la demande</h2>
<p>Pytest ne possède pas de méthode <code>setup()</code> et <code>teardown()</code>. A la place, il y a un mécanisme dit &#8220;de fixture&#8221;.</p>
<p>Il s&#8217;agit de marquer une fonction avec un <a href="http://sametmax.com/comprendre-les-decorateurs-python-pas-a-pas-partie-1/">décorateur</a>. Ensuite, si vous la déclarez en paramètre d&#8217;un test, pytest va automatiquement l&#8217;appeler au lancement de ce test. C&#8217;est une forme d&#8217;injection de dépendance, un peu à la angularjs.</p>
<p>C&#8217;est pas clair, hein ? Je sens que c&#8217;est pas clair.</p>
<p>Mais les exemples sont là pour ça :</p>
<pre lang="python">import pytest # cette fois il faut un import

# Je déclare une fixture, qui peut (ce n'est pas obligatoire), retourner
# quelque chose
@pytest.fixture()
def simple_comme_bonjour():
    return ('pomme', 'banane')

# Pour chaque test où je déclare le nom de la fixture en paramètre, pytest
# va appeler la fonction juste avant le test et passer son résultat
# (fut-il None), en argument de ce test
def test_get(simple_comme_bonjour):
    element = get(simple_comme_bonjour, 0)
    assert element == 'pomme'

def test_element_manquant(simple_comme_bonjour):
    element = get(simple_comme_bonjour, 1000, 'Je laisse la main')
    assert element == 'Je laisse la main'
</pre>
<p>L&#8217;avantage du système de fixtures, c&#8217;est qu&#8217;on n&#8217;est pas obligé d&#8217;exécuter la fixture pour tous les tests, seulement ceux pour lesquels on en a besoin. On peut combiner plusieurs fixtures de manière très souple, juste en déclarant plusieurs paramètres, sans avoir à faire des classes dans tous les sens. En fait, les fixtures peuvent avoir des fixtures en paramètre, histoire de faire des chaînes de dépendance.</p>
<p>Ici, il n&#8217;y a que l&#8217;exemple du setup, mais pas du tear down. Pour cela, on peut utiliser un autre type de fixture, qui demande l&#8217;utilisation d&#8217;un générateur :</p>
<pre lang="python">import pytest


# On passe de pytest.fixture() a pytest.yield_fixture()
@pytest.yield_fixture()
def simple_comme_bonjour():
    # tout ce qui est setup() va au dessus du yield. Ca peut etre vide.
    print('Avant !')

    # Ce qu'on yield sera le contenu du parametre. Ca peut etre None.
    yield ('pomme', 'banane')

    # Ce qu'il y a apres le yield est l'equivalent du tear down et peut être
    # vide aussi
    print('Apres !')

def test_get(simple_comme_bonjour):
    element = get(simple_comme_bonjour, 0)
    assert element == 'pomme'

def test_element_manquant(simple_comme_bonjour):
    element = get(simple_comme_bonjour, 1000, 'Je laisse la main')
    assert element == 'Je laisse la main'

def test_avec_echec(simple_comme_bonjour):
    element = get(simple_comme_bonjour, 1000, 'Je laisse la main')
    assert element == 'Je tres clair, Luc'
</pre>
<p>Comme pour avec unittest, le mot &#8220;Apres !&#8221; apparait bien malgré l&#8217;échec du 3eme test, on peut donc sans problème mettre des opérations de nettoyage dedans :</p>
<pre lang="python">$ py.test -s
============================= test session starts ==============================
platform linux2 -- Python 2.7.6 -- py-1.4.23 -- pytest-2.6.1
collected 3 items

test_get.py Avant !
.Apres !
Avant !
.Apres !
Avant !
FApres !


=================================== FAILURES ===================================
_______________________________ test_avec_echec ________________________________

simple_comme_bonjour = ('pomme', 'banane')

    def test_avec_echec(simple_comme_bonjour):
        element = get(simple_comme_bonjour, 1000, 'Je laisse la main')
>       assert element == 'Je tres clair, Luc'
E       assert 'Je laisse la main' == 'Je tres clair, Luc'
E         - Je laisse la main
E         + Je tres clair, Luc

test_get.py:33: AssertionError
====================== 1 failed,</pre>
<p>Notez que j&#8217;utilise l&#8217;option <code>-s</code>, qui demande à pytest de ne pas capturer la sortie de mon programme. Sinon je ne verrai pas mes prints.</p>
<p>Contrairement aux setup et tear down, on n&#8217;est pas obligé d&#8217;utiliser une fixture pour un test donné, il suffit de ne pas l&#8217;ajouter en paramètre, et ça ne sera pas lancé pour ce test là. Mais parfois, on veut qu&#8217;une fixture soit lancée partout et on se fiche de la valeur de retour. Dans ce cas, on peut utiliser <code>@pytest.fixture(autouse=True)</code>.</p>
<h2>Outils</h2>
<p>Pytest possède <a href="https://pypi.python.org/pypi?:action=search&#038;term=pytest&#038;submit=search">beaucoup</a> d&#8217;extensions tierces parties qui fournissent des fixtures. Par exemple, <a href="https://readthedocs.org/projects/pytest-django/">pytest-django</a> fournit des fixtures pour le client HTTP de test, l&#8217;override temporaire des settings et le reset de la base de données. La lib elle-même embarque quelques fixtures pratiques, dont :</p>
<ul>
<li><code>capsys</code> : permet de capturer ce qui a été écrit sur stdin/out et les lire depuis <code>capsys.readouterr</code>. Pratique pour tester une lib qui print des choses sans les retourner.</li>
<li><code>capsys</code> : permet de capturer ce qui a été écrit vers un file descriptor.</li>
<li><code>monkeypatch</code> : permet de modifier un objet, la modification sera inversée automatiquement à la fin du test. Contient <code>monkeypatch.setattr</code>, <code>monkeypatch.setitem</code>, <code>monkeypatch.setenv</code>, <code>monkeypatch.syspath_prepend</code>, <code>monkeypatch.chdir</code> et quelques autres.</li>
<li><code>tmpdir</code> : met à disposition un dossier temporaire avec un chemin unique pour le test donné.</li>
</ul>
<p>[LOL, mon hispter vient de se passer la main dans les cheveux, avec une emphase consciencieuse, comme un chat fait sa toilette. Je m'attends à ce qu'il se lèche les poils d'ici quelques minutes.]</p>
<p>Plus que cela, pytest vient également avec une pléthore d&#8217;options, et je ne saurais trop vous conseiller de lire l&#8217;output de <code>py.test --help</code> afin de faire le tour de ce qui s&#8217;offre à vous. Quelques exemples :</p>
<ul>
<li><code>-k EXPRESSION</code> : lance uniquement les tests qui contiennent cette chaîne. Pratique quand on a beaucoup de tests longs et qu&#8217;on travaille sur un en particulier.</li>
<li><code>-x</code> : s&#8217;arrêter à la première erreur. Pour le debug, ça évite de se taper tous les tests après ce qu&#8217;on veut explorer. </li>
<li><code>--doctest-modules</code>: lance les doctests de tous les fichiers *.py trouvés récursivement dans le dossier.</li>
<li><code>--ignore=PATH</code>: ignore un chemin. Je l&#8217;utilise souvent pour éviter que pytest n&#8217;aille lancer les tests des libs de mon virtualenv.</li>
</ul>
<p>Par ailleurs, pytest est très sociable et s&#8217;entend bien avec tous les outils de tests existants. Il va détecter les tests unittest, il prend en compte les fichiers <a href="https://testrun.org/tox/latest/">tox</a>.ini, et il existe même un plugin <a href="https://github.com/nose-devs/nose">nose</a> intégré.</p>
<p>D&#8217;ailleurs, j&#8217;utilise souvent un fichier tox.ini à la racine de mes tests contenant ceci :</p>
<pre>
[pytest]
addopts = --ignore="virtualenv" -s</pre>
<p>Cela ajoute automatiquement ces options à la commande py.test, puisque je les utilise tout le temps. Ça m&#8217;évite de les taper.</p>
<p>400 lignes pour dire, n&#8217;utilisez pas le module unittest, utilisez pytest.</p>
<p>Dans la prochaine partie, je me chargerai de faire le point sur les doctests, puis nous glisserons sur des sujets plus philosophiques comme &#8220;quand tester&#8221;, &#8220;quoi tester&#8221;, &#8220;comment tester&#8221;, &#8220;que faire si je suis testé positif&#8221;, etc.</p>
<p>Si le dieu de la procrastination le veut, on fera même un petit tour par les mocks, les outils d&#8217;intégration continue et le test end2end. C&#8217;est pas forcément du test unitaire, mais c&#8217;est du test, et je vais pas renommer mon dossier maintenant que ces belles URLs sont référencées pour Google.</p>


feed_id: http://sametmax.com/?p=12102
title: Un wifi bien de chez nous
uri: Un-wifi-bien-de-chez-nous
url: http://sametmax.com/un-wifi-bien-de-chez-nous/
content:
<p>La gare de Lyon est ma gare de Paris préférée. Celle de l&#8217;Est est vieillotte, Montparnasse est difficile d&#8217;accès, et la gare du Nord est un labyrinthe conçu pour s&#8217;assurer que vous ratiez votre train à 20 secondes près.</p>
<p>À la gare de Lyon, c&#8217;est lumineux, bien indiqué, sur la ligne A du RER. Et au guichet, une charmante dame avec la quarantaine bien portée me sourit en concluant :</p>
<blockquote><p>«On a le wifi dans le hall depuis cet été, monsieur »</p></blockquote>
<p>C&#8217;est sur cette remarque pleine d&#8217;entrain que je me suis assis dans un des sièges bordeaux encore libres. Diantre, des places assises et le Wifi ? La SNCF a-t-elle enfin demandé à un de ses cadres d&#8217;utiliser son propre service afin qu&#8217;il réalise que les gens qui patientent préfèrent ne pas le faire debout, et connectés ? Comble du bonheur, il y a des prises électriques, tenez-vous bien, à la hauteur des accoudoirs.</p>
<p>Vraiment, tout cela est suspect.</p>
<p>C&#8217;est que je m&#8217;étais préparé psychologiquement moi. Une inconfortable attente, vide de sens et bien remplie d&#8217;ennui. Je suis troublé, j&#8217;ai du mal a accepter ma bonne fortune.</p>
<p>Je clique donc sur mon petit icône en forme de part de pizza, et c&#8217;est presque bien, j&#8217;ai seulement besoin de choisir entre :</p>
<ul>
<li>SNCF-MOBILES (ah non, c&#8217;est sécurisé)</li>
<li>SNCF-VOYAGGES (ok, c&#8217;est sécu)</li>
<li>SNCF-WIBU (sécu)</li>
<li>*SNCF gare-gratuit (vous allez voir il est magnifique celui-là)</li>
<li>_Wifi Metropolis (qui redirige sur le même portail que *SNCF gare-gratuit)</li>
<li>LE_PREMI1ER_Wifi_Gratuit (compliment au stagiaire)</li>
<li>Relay_Wifi_Gratuit (les gars, sérieux, on est pas sur des noms de fichier de Windows 95)</li>
<li>AndroidAP5847 (un collègue d&#8217;infortune qui a du faire le deuil du wifi je suppose)</li>
<li>test *SNCF gare-gratuit (SI !)</li>
</ul>
<div id="attachment_12107" style="width: 586px" class="wp-caption aligncenter"><a href="media/8bc26035.01.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/08/01.png"><img src="media/8bc26035.01.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/08/01.png" alt="Catpure d&#039;écran de la liste des spots wifi" title="Ce qui est marrant, c&#039;est que la liste change régulièrement" width="576" height="487" class="size-full wp-image-12107" /></a><p class="wp-caption-text">Ce qui est marrant, c&#039;est que la liste change régulièrement</p></div>
<p>Pour vous retranscrire l&#8217;expérience au maximum, il faut que je vous fasse partager l&#8217;ambiance sonore pendant ma quequette du Graal.</p>
<p>D&#8217;abord il y a le haut parleur qui me rappelle toutes les 5 minutes que mon train a du retard, mais que ça va, il est en préparation.</p>
<p>Ensuite il y a le piano gare. Une initiative que j&#8217;ai toujours trouvé charmante jusqu&#8217;à ce qu&#8217;un amateur acharné décide de massacrer Yann Tiersen pendant l&#8217;intégralité de mon interminable temps d&#8217;attente.</p>
<p>Et bien entendu, alors que j&#8217;écris cette phrase, un môme a décidé de chialer derrière moi, en stéréo pour ne pas en rater une miette.</p>
<p>Mais retournons à nos wifis.</p>
<p>Je fais une tentative &#8211; quel naïf &#8211; sur notre SSID qui mélange mauvais goût capital et semi-1337-speak : LE_PREM1ER_Wifi_Gratuit. Je suis accueilli par ceci :</p>
<div id="attachment_12108" style="width: 508px" class="wp-caption aligncenter"><a href="media/c1c145a2.02.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/08/02.png"><img src="media/c1c145a2.02.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/08/02.png" alt="Capture d&#039;écran d&#039;un formulaire désuet" title="Si vous ne trouvez pas votre PDA, cherchez là où vous avez rangé votre minidisc" width="498" height="439" class="size-full wp-image-12108" /></a><p class="wp-caption-text">Si vous ne trouvez pas votre PDA, cherchez là où vous avez rangé votre minidisc</p></div>
<p>Évidement, si on valide le formulaire, il ne se passe absolument rien.</p>
<p>C&#8217;est pas grave, je passe à Relay_Wifi_Gratuit. Mais là, rien ne s&#8217;affiche, même pas de portail.</p>
<p>Bon, je tente *SNCF gare-gratuit, en me demandant si la petite étoile suppose qu&#8217;il y a une condition d&#8217;achat écrite en tout petit dans un des paquets ARP. Alors, là, on passe tout de suite au niveau sup.</p>
<p>On commence par un portail bien design avec une petit animation dans l&#8217;air du temps qu&#8217;on vous force à regarder :</p>
<div id="attachment_12109" style="width: 503px" class="wp-caption aligncenter"><a href="media/2a3013bf.03.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/08/03.png"><img src="media/2a3013bf.03.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/08/03.png" alt="Catpure d&#039;écran d&#039;un portail avec video" title="Les videos d&#039;intro sont les musiques d&#039;ascenseur de notre décénie" width="493" height="307" class="size-full wp-image-12109" /></a><p class="wp-caption-text">Les videos d&#039;intro sont les musiques d&#039;ascenseur de notre décénie</p></div>
<p>Et ensuite on a le choix entre la pilule rouge, qui ne marche pas, et la pilule jaune, qui vous redirige vers un formulaire magique :</p>
<div id="attachment_12110" style="width: 474px" class="wp-caption aligncenter"><a href="media/d9c6009d.04.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/08/04.png"><img src="media/d9c6009d.04.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/08/04.png" alt="Catpure d&#039;écran du choix du portail wifi" title="Souvient toi Néo, je t&#039;offre la vérité. Rien de plus. Et elle est toute pérave." width="464" height="322" class="size-full wp-image-12110" /></a><p class="wp-caption-text">Souvient toi Néo, je t&#039;offre la vérité. Rien de plus. Et elle est toute pérave.</p></div>
<p>Je dis magique car ça faisait longtemps que je n&#8217;avais pas ressenti tant d&#8217;émerveillement à la validation d&#8217;une balise &lt;form&gt;. Ça avait un petit goût de Disney :</p>
<div id="attachment_12111" style="width: 484px" class="wp-caption aligncenter"><a href="media/90da0277.05.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/08/05.png"><img src="media/90da0277.05.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/08/05.png" alt="Catpure d&#039;écran d&#039;une alerte javascript suite à la validation d&#039;un formulaire" title="Je vous avais parlé des formulaires REST. Voici un formulaire &quot;va t&#039;en&quot;." width="474" height="364" class="size-full wp-image-12111" /></a><p class="wp-caption-text">Je vous avais parlé des formulaires REST. Voici un formulaire &quot;va t&#039;en&quot;.</p></div>
<p>Bon, là, réflexe habituel, je reload. Peut être un problème de cache ou de réseau. Je me retape la vidéo et le formulaire., je désactive Adblock, au cas où. Je reload, je me retape la putain de video. Rien. Je commence avec ghostery, je me tape cette vidéo de merde pour la 4eme fois. Il ne reste plus qu&#8217;à tester, un autre navigateur. J&#8217;ai un petit chrome vierge de toute extension près pour ça, mais là, je suis carrément pris de cours :</p>
<div id="attachment_12112" style="width: 550px" class="wp-caption aligncenter"><a href="media/cd40b264.06.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/08/06.png"><img src="media/cd40b264.06.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/08/06.png" alt="Capture d&#039;écran du portail sous chrome : une page vide sans https" title="Pourquoi sécuriser une page vierge, en même temps ?" width="540" height="307" class="size-full wp-image-12112" /></a><p class="wp-caption-text">Pourquoi sécuriser une page vierge, en même temps ?</p></div>
<p>Notez la redirection sur une autre URL, et non sécurisée en plus, qui finit en page blanche.</p>
<p>Cocorico :</p>
<p><object width="420" height="315"><param name="movie" value="//www.youtube.com/v/SnZ5NzYe0Iw?version=3&amp;hl=fr_FR&amp;rel=0&amp;start=127&amp;end=148"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="//www.youtube.com/v/SnZ5NzYe0Iw?version=3&amp;hl=fr_FR&amp;rel=0&amp;start=127&amp;end=148" type="application/x-shockwave-flash" width="420" height="315" allowscriptaccess="always" allowfullscreen="true"></embed></object></p>
<p>A tout hasard, je retente _Wifi Metropolis. Maintenant que je sais qu&#8217;ils font du sniffing, le fait d&#8217;avoir deux fois le même portail sous des alias me fais dire que ça peut marcher. Et bingo, ici la pilule rouge marche et me donne 20 minutes d&#8217;internet illimité gratuit.</p>
<p>La seule bonne surprise, c&#8217;est que quand ils disent internet, c&#8217;est bien de l&#8217;internet, et pas du Web bridé. J&#8217;ai accès à SSH et IRC, je pip sans blocage de proxy, et tout est très fluide. Mais bon entre la rédaction de l&#8217;article, les tentatives de connections et la constante interruption pour écouter les annonces afin de ne pas rater mon train, je dois partir.</p>
<p>Snif.</p>
<p>Ce faisant, j&#8217;ai croisé un dispositif d&#8217;étude satisfaction client qui frise le foutage de gueule :</p>
<div id="attachment_12113" style="width: 490px" class="wp-caption aligncenter"><a href="media/6d484dd2.Photo0018.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2014/08/Photo0018.jpg"><img src="media/6d484dd2.Photo0018.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2014/08/Photo0018.jpg" alt="Photo du dispositif de mesure de satisfaction client" title="C&#039;est comme les réductions pour lesquelles il faut envoyer une lettre pour obtenir le remboursement après achat..." width="480" height="400" class="size-full wp-image-12113" /></a><p class="wp-caption-text">C&#039;est comme les réductions pour lesquelles il faut envoyer une lettre pour obtenir le remboursement après achat...</p></div>
<p>A gauche, un bouton pour dire en une seconde que tout va bien. A droite, un QR code pour dire que vous connecter à un site pour exprimez ce que n&#8217;aimez pas. Je crois que je comprends pourquoi le wifi est si dur à avoir :)</p>
<p>Bon, ça concerne l&#8217;art en gare, donc pas de défouloir possible pour moi.</p>
<p>Enfin, je râle, mais contrairement à beaucoup de français, j&#8217;aime bien la SNCF. Après avoir voyagé dans bien des pays, où le train est cher, inconfortable, peu accueillant et avec des horaires auxquelles on ne peut accorder aucune confiance (et ne croyez pas que je parles du tiers-monde, essayez les UK&#8230;), je suis même assez épaté.</p>
<p>Ils gèrent un flux de voyageurs gigantesque et pas toujours très malins, des crises tous les jours, plutôt bien d&#8217;ailleurs, dans l&#8217;intégralité de la France, y compris les petits bourgades de campagne de mon enfance. On est souvent bien accueilli. Les trains sont confortables. Les tarifs sont raisonnables. Et croyez moi quand je vous dis que jusqu&#8217;à 4h de retard, on est dans la tranche haute de la fiabilité sur les grandes lignes partout dans le monde. Sauf au Japon, mais les androïdes ne comptent pas.</p>
<p>Même si mon train était en retard. Même si ils se sont gourés dans la numérotation des voitures. Même si ils m&#8217;ont mis à côté d&#8217;un malpoli qui écoute sa musique à fond et me fait profiter de chacune des basses de son morceau sans goût ni originalité. Même si ils ne sont pas foutu de faire en Wifi ce que MacDo fait depuis plus de 10 ans.</p>
<p>Hey, je peux être à Lyon en 3h. Et l&#8217;uniforme gris de la contrôleuse lui fait un super cul.</p>
<p>Je vous laisse, mon train est arrêté en pleine voie, c&#8217;est palpitant.</p>


feed_id: http://sametmax.com/?p=12134
title: De retour, et déjà dans la merde :)
uri: De-retour-et-déjà-dans-la-merde-)
url: http://sametmax.com/de-retour-et-deja-dans-la-merde/
content:
<p>Bon, le blog repart, et pour bien commencer, on a une partition corrompue. Ce qui explique les hauts et les bas du blog de ces derniers jours : pas d&#8217;images, categs / tags vides, lenteurs, etc.</p>
<p>En fait, c&#8217;est le ext4 de /tmp qui a été monté en read-only par le système pour éviter de tout pêter. Mais du coup, PHP et MailleScule n&#8217;aiment pas trop.</p>
<p>La solution temporaire a été de redem les deux process et bidouiller leur config pour que leurs fichiers temp tapent dans une partition saine, le temps de resoudre le problème.</p>
<p>Comme l&#8217;installation est bidouillée de chez bidouillée, on a vraiment pas envie de tout réinstaller, donc on fait de l&#8217;acharnement thérapeutique pour sauver ce serveur.</p>
<p>Bref, vive l&#8217;auto-hébergement !</p>


feed_id: http://sametmax.com/?p=12140
title: Le sperme, ça attache au fond
uri: Le-sperme-ça-attache-au-fond
url: http://sametmax.com/le-sperme-ca-attache-au-fond/
content:
<p>Sur le blog, on parle de S&#038;M, mais peu de SM. La raison pour cela c&#8217;est qu&#8217;on est tout simplement pas des experts dans le domaine, et on reste dans la domination soft, bien que parfois on déborde un peu.</p>
<p>Malgré tout, en discutant avec des amis, je me suis aperçu que peu de gens ont vraiment goûté à la domi en dehors de videos. La raison est double. </p>
<p>D&#8217;abord, c&#8217;est n&#8217;est pas courant de tomber sur une personne qui soit vraiment capable de se trouver de l&#8217;autre côté de la laisse. </p>
<p>Ensuite, c&#8217;est socialement compliqué. Voyez-vous, on ne peut pas demander à quelqu&#8217;un si on peut le ou la soumettre, ça va exactement à l&#8217;encontre du principe de soumission qui, psychologiquement, n&#8217;admet pas la demande de permission. Et un ou une soumise va rarement demander à quelqu&#8217;un de le faire, car c&#8217;est facile de se griller dans un groupe. Parfois même, la personne ne sait pas qu&#8217;elle aime ça.</p>
<p>L’œuf, la poule, tout ça.</p>
<p>Voici donc un petit récit de ma dernière séance, pour que vous ayez une idée de ce que ça peut donner dans la vraie vie. Je répète encore une fois que malgré nos exactions, ceci n&#8217;est pas notre lot quotidien à Max et à Moi. On vous raconte les trucs qui valent le coup d&#8217;être publiés. C&#8217;est pas comme ça tous les jours à la maison, hein.</p>
<p>Lucie aime être soumise. Je le sais, par bouche à oreille. Un ami a eu une aventure avec elle, et sachant que j&#8217;avais couché avec la veille, il m&#8217;en a touché deux mots. Après s&#8217;être vu quelques fois, la miss est en confiance et je décide qu&#8217;il est temps de se faire une petite session.</p>
<p>Et ça, ça s&#8217;organise.</p>
<p>Certains aiment bien le faire au fil de l&#8217;eau, au gré de leur créativité. Moi j&#8217;aime bien scénariser, et donc préparer à l&#8217;avance, quitte à improviser si mon plan tombe à la flotte, ce qui arrive plus souvent que je le voudrais.</p>
<p>D&#8217;abord, choisir une date pour la faire venir. Pas besoin de prétexte, elle a envie de me voir, ce qui est déjà ça de moins à s&#8217;occuper. Mais il faut choisir un moment en journée où on a rien de prévu pour ne pas avoir à se presser, et surtout où il n&#8217;y aura personne à la maison. Je vous rappelle que je vis en colocation.</p>
<p>Ensuite, quelques accessoires. Une pote me fournit des attaches psychiatriques. Ce sont des sortes de ceintures conçues pour sangler les bras et les jambes des patients difficiles sur les lits d’hôpital. C&#8217;est fantastique car très rapide et facile à positionner (c&#8217;est à base d&#8217;une clé aimantée), très solide (on peut tirer dessus très fort) mais pensé pour ne pas blesser quelqu&#8217;un qui force dessus. C&#8217;est confortable, assez joli, et suffisamment angoissant.</p>
<p>Je les attache sur le devant de ma mezzanine, j&#8217;ai décidé qu&#8217;elle sera debout. La domination, c&#8217;est une suite de décisions, puisque c&#8217;est une prise de contrôle. </p>
<p>Puis je découpe un bout de scotch gris que je mets à portée de main, pour la bâillonner. Elle est chanteuse, et les ball gags ne fonctionnent absolument pas pour la mettre en sourdine.</p>
<p>Pour finir, il lui faut de quoi indiquer qu&#8217;elle atteint sa limite sans pouvoir prononcer un <a href="http://sametmax.com/le-mot-de-la-fin/">safe word</a> puisqu&#8217;elle ne pourra pas parler. Je prends donc un maracasse. </p>
<p>Ah, oui, je rajoute un couteau de chasse bien aiguisé avec lequel je planifie de découper ses vêtements, et donc un budget pour lui racheter les dits apparats après. Qui casse paie. </p>
<p>Il n&#8217;y a plus qu&#8217;à la faire venir, et à attendre.</p>
<p>Je déteste l&#8217;attente dans ces moments là. Max est tout le contraire, ça l&#8217;excite. Même quand il va ramener des putes de bar, il passe la nuit là-bas car il aime prendre son temps. Moi ça me stresse. J&#8217;ai le cœur qui bat à 100 à l&#8217;heure, il y a tellement de choses qui peuvent foirer. Et foirer grave. Le scénar qui ne colle pas et on a l&#8217;air ridicule, le scénar qui colle trop et la meuf qui me prend pour un psychopathe, les voisins qui appellent les flics, le couteau qui glisse et qui la blesse&#8230; Il faut pas faire ça quand on a la poisse.</p>
<p>Finalement elle arrive à l&#8217;heure dite (Dieu, que j&#8217;aime les femmes ponctuelles !), en tenue légère, ce qui m&#8217;arrange bien. On s&#8217;embrasse tendrement, et je fais avec elle quelques pas de valse pour la rapprocher des attaches. </p>
<p>On se chauffe un peu, vêtement par vêtement, et je tâte le terrain. Avec un petit sourire, je lui tends un bras, et l&#8217;attache, le regard coquin. Elle se laisse faire. C&#8217;est bon signe, j&#8217;attache donc le second, et lui glisse le maracasse dans une main. Je lui explique les règles du jeu : &#8220;Secoue et j&#8217;arrête sur le coup, lâche, et je te détache&#8221;. J&#8217;attends quelques secondes sans rien dire pour voir si elle a bien compris. Elle ne panique pas. Bien. Mais ça va changer, car on passe à la mise en scène.</p>
<p>Changement de rythme. </p>
<p>Je fais passer sans transition mon visage d&#8217;un sourire doux à un air dur, et je la bâillonne sans crier gare.</p>
<p>&#8220;T&#8217;es vraiment conne Lucie. Tu connais un mec depuis, quoi, une semaine ? Et tu le laisses te faire venir dans une maison vide et t&#8217;attacher à un lit sans te poser de question ? C&#8217;est naïf.&#8221;</p>
<p>Je verrouille ma porte, et baisse le store, heureusement électrique, de ma fenêtre. Je prends mon temps.</p>
<p>&#8220;Personne ne pourra t&#8217;entendre. Et maintenant personne ne pourra te voir.&#8221;</p>
<p>Je la sens mal à l&#8217;aise, en train de se demander si je joue la comédie ou si elle est tombée sur un serial killer.</p>
<p>Je sors le couteau de chasse, et plongeant mes yeux dans les siens, je peux voir que le doute commence à l&#8217;angoisser. Mais elle a le maracasse, et elle n&#8217;essaye pas de s&#8217;en servir. Elle m&#8217;expliquera après qu&#8217;au début elle avait complètement oublié qu&#8217;elle l&#8217;avait dans la main.</p>
<p>Je lui enlève ce qui reste de ses vêtements, en jouant avec la lame sur son corps. Si vous faites ça, faites très attention, l&#8217;accident est vraiment vite arrivé. Je suis très concentré pendant toute la procédure, entre le jeu d&#8217;acteur et mon désir d&#8217;éviter de lui trancher la jugulaire.</p>
<p>Il me reste le soutif et je n&#8217;ai encore rien coupé, alors je le fends en deux. Elle se débat un peu, je lui mets une baffe et un rappel oral à l&#8217;ordre. Elle se calme, et mouille instantanément. Je peux sentir la cyprine alors que je suis à hauteur de son cou. Pas de chic-chic. C&#8217;est gagné, je ne finirai pas en garde à vue ce soir.</p>
<p>J&#8217;avais prévu de faire durer le truc plus longtemps, mais vu que la demoiselle est prête, et que j&#8217;ai vraiment très, très envie de la baiser, j&#8217;accélère le programme. Je pousse un fauteuil, et la colle dessus de manière très  inconfortable. À ce stade je ne donne plus d&#8217;ordre, je la prends par les cheveux et la fais bouger au gré de mes envies. Et elle obéit. </p>
<p>Elle a les genoux sur le siège, le ventre sur le dossier, la tête dans le vide et les bras tendus, toujours attachés en l&#8217;air. Je tire l&#8217;assise pour allonger le vide entre sa position et la mezza, elle doit forcer un peu pour garder sa posture.</p>
<p>Je la prends sans plus attendre, et sans ménagement. Je la pénètre presque violemment, mais elle est plus excitée que si je l&#8217;avais léchée pendant 20 minutes, et ça rentre tout seul. Elle ne m&#8217;a pas vu mettre la capote, je me demande si elle se demande.</p>
<p>Je la tire en arrière par sa belle tignasse dorée, je la pousse en avant pour qu&#8217;elle se mange le canapé, je bouge ses jambes, les lève, les baisse. Je la fesse, évidement. Puis je lui colle un doigt dans le cul.</p>
<p>Premier et unique son de maracasse. La demoiselle n&#8217;aime pas l&#8217;anal. Soit. Je retire mon auriculaire.</p>
<p>Le respect de son souhait malheureusement, inverse la balance de la relation. Il faut donc que je la soumette à nouveau. Je ne l&#8217;enculerai pas, mais je la réprimande, et je vais la punir. </p>
<p>Je la mets en équilibre sur le dossier du fauteuil, les jambes écartées, elle est debout à un mètre du sol, mais toujours attachée. J&#8217;ai une idée.</p>
<p>Je vais chercher une tondeuse à barbe, et je tonds la petite touffe de poils qui lui reste au niveau de la chatte, puis je lui cale l&#8217;engin encore vibrant dans le vagin, les dents à l&#8217;extérieur, bien entendu.</p>
<p>&#8220;Si tu le fais tomber, tu en prends une.&#8221;</p>
<p>Et je vais me faire un thé. Je prends mon temps, faire bouillir l&#8217;eau, choisir sa marque, mettre ça dans une jolie théière.</p>
<p>Je ramène tout ça, et je laisse infuser. Pendant que les feuilles délivrent leurs senteurs, je monte sur le lit, délivre sa bouche pour lui donner immédiatement de quoi s&#8217;occuper. Elle me suce avec beaucoup d&#8217;ardeur, et elle est assez douée, bien que moins qu&#8217;elle ne le croit. Elle s&#8217;en était vanté. </p>
<p>Elle arrête, avec un regard de défi, et reprend une claque sans plus attendre. Elle y remet deux fois plus de cœur, j&#8217;entends sa gorge glousser, la tondeuse vibrer, et j&#8217;ai envie de venir. </p>
<p>Mais pas comme ça.</p>
<p>Je la rabaisse, lui disant qu&#8217;elle s&#8217;y prend tellement mal que j&#8217;allais devoir faire le boulot moi-même. Je me masturbe au dessus d&#8217;elle, et finis sur son visage.</p>
<p>Je retourne vers elle, et lui annonce qu&#8217;elle a été sage, et a le droit de se faire libérer un bras. Lequel choisit-elle ? Le droit ? Je détache le gauche. Puis je m&#8217;en vais boire mon thé. Lentement. Gorgée par gorgée.</p>
<p>Je retourne à mon mouton, ses petits yeux bleus sont ravissants au milieu de son visage souillé qu&#8217;elle a maladroitement tenté d&#8217;essuyer avec son bras valide. C&#8217;est une victime idéale, la peau claire, l&#8217;air innocent&#8230; Je lui détache l&#8217;autre main et lui passe la sangle autour du cou, la promenant ainsi jusqu&#8217;à mon ordinateur, où j&#8217;entreprends de checker mes mails avec une seconde tasse de thé.</p>
<p>Elle ne dit rien, je ne veux pas qu&#8217;elle s&#8217;ennuie, et lui commande de me lécher les pieds, n&#8217;ayant pas du tout envie de me faire pomper à l&#8217;instant. C&#8217;est très agréable, de se faire lécher les pieds.</p>
<p>Elle commence à avoir la langue sèche, alors je lui dépose une tasse et l&#8217;autorise à laper. Et je continue ma lecture du shaarli de Sebsauvage, par flux RSS car son design m&#8217;arrache les yeux.</p>
<p>Finalement, je la détache, je l&#8217;embrasse amoureusement. C&#8217;est terminé. Je la câline. La rassure. Cette phase là est importante. Elle réinstaure le respect. Sépare le jeu de la réalité. Remet les pendules à l&#8217;heure, les points sur les G&#8230;</p>
<p>Elle me confie ses peurs, elle tremble un peu. Elle a adoré. Je suis soulagé. J&#8217;avais peur moi aussi, tellement peur que ça rate. Mais je ne lui ai certainement pas dit ça. A la place, je lui propose d&#8217;aller faire Pretty Woman pour remplacer son haut lacéré.</p>
<p>Pendant qu&#8217;elle était dans mes bras, j&#8217;ai réfléchi. Réfléchi à la prochaine fois. Pas pour tout de suite. C&#8217;est vraiment trop de boulot.</p>


feed_id: http://sametmax.com/?p=12162
title: Quel ordi du coup ?
uri: Quel-ordi-du-coup
url: http://sametmax.com/quel-ordi-du-coup/
content:
<p>Je vous ai saoulé avec le <a href="http://sametmax.com/recherche-config-pour-relation-serieuse/">topic</a> sur la nouvelle bécane que je devrais acheter, donc la moindre politesse c&#8217;est de vous communiquer le choix final.</p>
<p>En gros, beaucoup de gens sont allés dans le sens qu&#8217;un écran brillant, c&#8217;était pas la mer à boire, surtout avec les traitements anti-reflets actuels.</p>
<p>Du coup je me suis laissé tenté, et j&#8217;ai craqué pour l&#8217;<a href="https://en.wikipedia.org/wiki/ATIV_Book_9">ativ book 9</a> qui a tout ce que je veux, à part une écran mat. </p>
<p>La machine est fantastique : légère, rapide, un touchpad et un clavier excellents, et un très bon son. L&#8217;autonomie est loin de battre des records, particulièrement sous Linux, mais ce dernier s&#8217;installe facilement à condition de désactiver le secure boot.</p>
<p>En revanche, <strong>je hais l&#8217;écran brillant de toute mon âme.</strong></p>
<p>On m&#8217;a menti. Non seulement le traitement anti-reflet marche queud&#8217;, mais en prime ce n&#8217;est pas que sur mon hamac qu&#8217;il me gène. Dès que je suis trop près d&#8217;une fenêtre, il faut éviter de travailler sur un fond trop sombre. C&#8217;est con, mon thême Sublime Text préféré est noir. Ça me fait pareil sur le mac de Max, putain de techno pourrie.</p>
<p>L&#8217;écran est tactile, ce qui ne sert absolument à rien pour mon usage. Et on a une très haute résolution de mes couilles à 12 milliards de pouces genre je copie Retina parce que c&#8217;est la mode. Résolution inutilisable sans un zoom pour lire le texte, et pour laquelle très peu d&#8217;applications sont adaptées. Je ne parle même pas des jeux. </p>
<p>Heureusement que la luminosité de l&#8217;écran est énorme sinon ça m&#8217;aurait dégoûté.</p>
<p>Bref, Du coup je down grade mon affichage. Qui aurait cru que je fasse ça une fois dans ma vie ? Et je vais acheter un filtre matifiant.</p>


feed_id: http://sametmax.com/?p=12184
title: Qu’est-ce qu’une API ?
uri: Qu-est-ce-qu-une-API
url: http://sametmax.com/quest-ce-quune-api/
content:
<p>L&#8217;API, pour Application Programming Interface, est la partie du programme qu&#8217;on expose officiellement au monde extérieur pour manipuler celui-ci. L&#8217;API est au développeur ce que l&#8217;UI est à l&#8217;utilisateur : de quoi entrer des données et récupérer la sortie d&#8217;un traitement.</p>
<h2>L&#8217;API au sens original</h2>
<p>Initialement, une API regroupe un ensemble de fonctions ou méthodes, leurs signatures et ordre d&#8217;usage pour obtenir un résultat.</p>
<p>Par exemple, imaginons que je fasse une lib pour botter des culs en Python, <code>bottage.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> senerver<span style="color: black;">&#40;</span>moment<span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;"># ...</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> botter<span style="color: black;">&#40;</span>cul<span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;"># ...</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> init<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;"># ...</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">if</span> __name__ <span style="color: #66cc66;">==</span> <span style="color: #483d8b;">&quot;__main__&quot;</span>:
    init<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Je vais l&#8217;utiliser ainsi :</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> bottage <span style="color: #ff7700;font-weight:bold;">import</span> senerver<span style="color: #66cc66;">,</span> botter
&nbsp;
senerver<span style="color: black;">&#40;</span>now<span style="color: black;">&#41;</span>
botter<span style="color: black;">&#40;</span>le_cul_de_ce_con<span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Les deux fonctions <code>senerver()</code> et <code>botter()</code> sont mes points d&#8217;entrée pour cette action. Je n&#8217;utilise pas <code>init()</code>, qui est un code interne à la lib et ne me regarde pas.</p>
<p>Donc leurs noms et leurs paramètres ainsi que leurs types sont l&#8217;API de ma lib, ce qui m&#8217;est exposé pour l&#8217;utiliser.</p>
<p>Si on veut rentrer dans des subtilités, on dira en fait que <code>senerver()</code> et <code>botter()</code> font partie de l&#8217;API publique, c&#8217;est à dire de ce qui est manipulable par un utilisateur de la lib. A l&#8217;inverse, <code>init()</code> fait partie de l&#8217;API privée, c&#8217;est à dire ce qui est manipulable par les développeurs de la lib. Mais quand on parle d&#8217;API sans préciser, on parle de l&#8217;API publique.</p>
<h2>Changement d&#8217;API</h2>
<p>En informatique, on peut généralement exposer les choses de plusieurs manières différentes. Je peux changer mon API :</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;">datetime</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> senerver<span style="color: black;">&#40;</span>moment<span style="color: #66cc66;">=</span><span style="color: #008000;">None</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> moment:
        moment <span style="color: #66cc66;">=</span> <span style="color: #dc143c;">datetime</span>.<span style="color: #dc143c;">datetime</span>.<span style="color: black;">utcnow</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    <span style="color: #808080; font-style: italic;"># ...</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> botter<span style="color: black;">&#40;</span>cul<span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;"># ...</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> init<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;"># ...</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">if</span> __name__ <span style="color: #66cc66;">==</span> <span style="color: #483d8b;">&quot;__main__&quot;</span>:
    init<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Ici, j&#8217;ai changé mon API pour rendre le paramètre <code>moment</code> facultatif afin de faciliter la vie des utilisateurs de la libs.</p>
<p>Et là on aborde un point très important du concept : la stabilité d&#8217;une API.</p>
<p>Puisque l&#8217;API est ce qu&#8217;on expose au monde extérieur, le monde extérieur va l&#8217;utiliser d&#8217;une certaine façon. Si on change cette manière de l&#8217;utiliser dans une version suivante, au moment de la mise à jour, on va casser leur code si on ne fait pas attention.</p>
<p>Par exemple, ici je rends un paramètre facultatif : ça ne craint pas grand-chose. Mais si j&#8217;avais fait l&#8217;inverse ? J&#8217;avais un paramètre facultatif, et soudain je le rends obligatoire. Toutes les personnes qui n&#8217;ont pas passé le paramètre vont soudain avoir un plantage s&#8217;ils passent à la nouvelle version de la lib car l&#8217;API a changé.</p>
<p>C&#8217;est donc une seconde définition de l&#8217;API : l&#8217;API est une promesse, un contrat entre l&#8217;auteur d&#8217;un code et ceux qui vont utiliser ce code. Cette promesse est &#8220;voici ce que vous pouvez utiliser sereinement dans votre programme, je ne vais pas tout péter demain&#8221;.</p>
<p>Cette promesse est plus ou moins bien respectée selon les projets. Python, par exemple, a un historique exemplaire de stabilité d&#8217;API, et n&#8217;a cassé la compatibilité qu&#8217;une fois, avec Python 3, donnant 10 ans aux développeurs pour s&#8217;adapter.</p>
<p>Dans tous les cas, si une lib est beaucoup utilisée et que son développeur a le sens des responsabilités, elle évolue plus doucement. Pour cette raison, il faut faire attention au choix qu&#8217;on fait dans le style de son API, sous peine de ne pas pouvoir le changer plus tard.</p>
<p>En effet, on peut tout à faire écrire le même code dans des tas de styles différents. Ainsi, je pourrais botter des culs avec une API orientée objet :</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;">class</span> Colere:
&nbsp;
    <span style="color: #66cc66;">@</span><span style="color: #008000;">classmethod</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> global_init<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
        <span style="color: #808080; font-style: italic;"># ...</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span>moment<span style="color: black;">&#41;</span>:
        <span style="color: #808080; font-style: italic;"># ...</span>
        <span style="color: #008000;">self</span>._senerver<span style="color: black;">&#40;</span>moment<span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> _senerver<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
        <span style="color: #808080; font-style: italic;"># ...</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> botter<span style="color: black;">&#40;</span>cul<span style="color: black;">&#41;</span>:
        <span style="color: #808080; font-style: italic;"># ...</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">if</span> __name__ <span style="color: #66cc66;">==</span> <span style="color: #483d8b;">&quot;__main__&quot;</span>:
    Colere.<span style="color: black;">global_init</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Mon bottage de cul n&#8217;a plus du tout le même goût à l&#8217;usage :</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> bottage <span style="color: #ff7700;font-weight:bold;">import</span> colere
c <span style="color: #66cc66;">=</span> Colere<span style="color: black;">&#40;</span>now<span style="color: black;">&#41;</span>
c.<span style="color: black;">botter</span><span style="color: black;">&#40;</span>un_aperi_cul<span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Mon programme fait la même chose, mais mon API est différente. Notez le <code>_senerver()</code> qui est préfixé d&#8217;un underscore, une convention en Python pour dire que cette méthode doit être considérée comme ne faisant pas partie de l&#8217;API publique, donc à ne pas utiliser depuis l&#8217;extérieur. En effet, il n&#8217;y a pas de méthode privée en Python.</p>
<h2>Qualités d&#8217;une API</h2>
<p>On a vu que la stabilité était une qualité importante d&#8217;une API. Mais il y en a d&#8217;autres. Notamment la performance et l&#8217;ergonomie, généralement deux notions qui s&#8217;affrontent.</p>
<p>Pour l&#8217;ergonomie, il s&#8217;agit de rendre facile les usages qu&#8217;on fait le plus couramment, et rendre possible les usages les plus ardus. Prenez l&#8217;exemple d&#8217;une requête HTTP avec paramètre POST sur un site qui a besoin de cookies d&#8217;une requête précédente. Pas un usage incroyablement complexe a priori&#8230;</p>
<p>Avec la stdlib de Python, ça donne ç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;">import</span> <span style="color: #dc143c;">urllib</span>
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">urllib2</span>
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">cookielib</span>
&nbsp;
cookie_jar <span style="color: #66cc66;">=</span> <span style="color: #dc143c;">cookielib</span>.<span style="color: black;">CookieJar</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
opener <span style="color: #66cc66;">=</span> <span style="color: #dc143c;">urllib2</span>.<span style="color: black;">build_opener</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">urllib2</span>.<span style="color: black;">HTTPCookieProcessor</span><span style="color: black;">&#40;</span>cookie_jar<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #dc143c;">urllib2</span>.<span style="color: black;">install_opener</span><span style="color: black;">&#40;</span>opener<span style="color: black;">&#41;</span>
<span style="color: #dc143c;">urllib2</span>.<span style="color: black;">urlopen</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'http://site.com'</span><span style="color: black;">&#41;</span>
&nbsp;
data <span style="color: #66cc66;">=</span> <span style="color: #dc143c;">urllib</span>.<span style="color: black;">urlencode</span><span style="color: black;">&#40;</span><span style="color: black;">&#123;</span><span style="color: #483d8b;">&quot;nom&quot;</span>: <span style="color: #483d8b;">&quot;valeur&quot;</span><span style="color: black;">&#125;</span><span style="color: black;">&#41;</span>
rsp <span style="color: #66cc66;">=</span> <span style="color: #dc143c;">urllib2</span>.<span style="color: black;">urlopen</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'http://site.com/autre/page'</span><span style="color: #66cc66;">,</span> data<span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>rsp.<span style="color: black;">read</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>La même chose avec la lib <a href="http://docs.python-requests.org/en/latest/">requests</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;">import</span> requests
&nbsp;
request.<span style="color: black;">get</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'http://site.com'</span><span style="color: black;">&#41;</span>
res <span style="color: #66cc66;">=</span> request.<span style="color: black;">post</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'http://site.com/autre/page'</span><span style="color: #66cc66;">,</span> data<span style="color: #66cc66;">=</span><span style="color: black;">&#123;</span><span style="color: #483d8b;">&quot;nom&quot;</span>: <span style="color: #483d8b;">&quot;valeur&quot;</span><span style="color: black;">&#125;</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>res.<span style="color: black;">content</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Il ne s&#8217;agit pas juste du fait qu&#8217;il y ait beaucoup moins de lignes pour le faire. La facilité à découvrir comment faire dans le deuxième cas est exemplaire : en lisant, on comprend le code. En bidouillant dans le shell, on peut sans doute trouver tout ça. On n&#8217;a pas besoin de se poser la question de ce qu&#8217;est une jar, l&#8217;url encoding, etc.</p>
<p>Le premier exemple est non seulement verbeux, mais très, très difficile à trouver soi-même. En fait, même avec la doc sous les yeux, ce n&#8217;est pas évident d&#8217;arriver à ce résultat, et on y arrivera après des essais douloureux.</p>
<p>Le deuxième exemple est plus ergonomique que le premier.</p>
<p>Mais l&#8217;ergonomie a généralement un coût : celui de la performance.</p>
<p>Imaginez que j&#8217;ai la lib de bottage de fion sous forme fonctionnelle :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">datetime</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> senerver<span style="color: black;">&#40;</span>moment<span style="color: #66cc66;">=</span><span style="color: #008000;">None</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> moment:
        moment <span style="color: #66cc66;">=</span> <span style="color: #dc143c;">datetime</span>.<span style="color: #dc143c;">datetime</span>.<span style="color: black;">utcnow</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    <span style="color: #808080; font-style: italic;"># ...</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> botter<span style="color: black;">&#40;</span>cul<span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;"># ...</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> init<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;"># ...</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">if</span> __name__ <span style="color: #66cc66;">==</span> <span style="color: #483d8b;">&quot;__main__&quot;</span>:
    init<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Je veux la rendre plus ergonomique. Je sais qu&#8217;il faut obligatoirement s&#8217;énerver pour botter un cul, et je décide donc de cacher cette fonction et l&#8217;appeler automatiquement :</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> moment
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> _senerver<span style="color: black;">&#40;</span>moment<span style="color: #66cc66;">=</span><span style="color: #008000;">None</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> moment:
        moment <span style="color: #66cc66;">=</span> <span style="color: #dc143c;">datetime</span>.<span style="color: #dc143c;">datetime</span>.<span style="color: black;">utcnow</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    <span style="color: #808080; font-style: italic;"># ...</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> botter<span style="color: black;">&#40;</span>cul<span style="color: #66cc66;">,</span> moment<span style="color: #66cc66;">=</span><span style="color: #008000;">None</span><span style="color: black;">&#41;</span>:
    _senerver<span style="color: black;">&#40;</span>moment<span style="color: black;">&#41;</span>
    <span style="color: #808080; font-style: italic;"># ...</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> init<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;"># ...</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">if</span> __name__ <span style="color: #66cc66;">==</span> <span style="color: #483d8b;">&quot;__main__&quot;</span>:
    init<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Dans la plupart des cas, ça va aider mon public :</p>
<p>Au lieu de devoir savoir qu&#8217;il faut s&#8217;énerver avant de botter, ils ont juste à botter :</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> bottage <span style="color: #ff7700;font-weight:bold;">import</span> botter
botter<span style="color: black;">&#40;</span>cul_de_jatte<span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>J&#8217;ai identifié que c&#8217;était l&#8217;usage le plus courant, donc c&#8217;est une amélioration. Mais ça a un prix pour une petite partie de mes utilisateurs : les très gros botteurs de cul. Ceux qui bottent des culs par centaine.</p>
<p>Avant, ils pouvaient 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;">from</span> bottage <span style="color: #ff7700;font-weight:bold;">import</span> senerver<span style="color: #66cc66;">,</span> botter
senerver<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">for</span> cul <span style="color: #ff7700;font-weight:bold;">in</span> rang_doigons:
    botter<span style="color: black;">&#40;</span>cul<span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Mais maintenant, faisant :</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> bottage <span style="color: #ff7700;font-weight:bold;">import</span> botter
<span style="color: #ff7700;font-weight:bold;">for</span> cul <span style="color: #ff7700;font-weight:bold;">in</span> rang_doigons:
    botter<span style="color: black;">&#40;</span>cul<span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Ils ont un appel à <code>_senerver()</code> à chaque tour de boucle, et donc un appel à <code>datetime.utcnow()</code> aussi !</p>
<p>Bien entendu, il est possible de remédier à cette situation, mais cet article n&#8217;est pas là pour vous expliquer comment créer une belle API. Ce serait néanmoins un très bon article.</p>
<p>Ici, je vous montre simplement qu&#8217;en facilitant, on suppose d&#8217;un usage, et ça peut se faire au détriment des autres. L&#8217;automatisme a tendance à retirer de la marge de manœuvre.</p>
<p>Une bonne API va donc proposer un moyen automatique de faire les opérations de tous les jours, va lui donner une forme (nom, ordre des actions, organisation, etc) ET un moyen de faire des choses compliquées ou performantes. Ce qui va rendre l&#8217;API plus riche, donc plus lourde, avec une plus grosse doc, etc.</p>
<p>Tout a un coût.</p>
<h2>API Web</h2>
<p>Jusqu&#8217;ici vous avez vu l&#8217;API d&#8217;une bibliothèque, mais il existe d&#8217;autres genres d&#8217;API. L&#8217;un est devenu particulièrement populaire depuis le milieu des années 2000 : l&#8217;API Web.</p>
<p>L&#8217;API Web est comme l&#8217;API précédente ce qui est exposé à l&#8217;extérieur pour manipuler un programme. Entrées. Sorties. Mais il y a plusieurs différences :</p>
<ul>
<li>Ce n&#8217;est pas une lib qu&#8217;on manipule, c&#8217;est en général un service complet.</li>
<li>On n&#8217;utilise pas le langage dudit code pour le manipuler, mais un protocole Web.</li>
<li>Les appels passent par le réseau.</li>
</ul>
<p>Il existe de nombreux protocoles qui permettent de faire une API Web : SOAP, REST, XML RPC, WAMP etc.</p>
<p>Aujourd&#8217;hui, les API Web les plus populaires utilisent majoritairement un protocole pseudo-REST avec en encoding JSON.</p>
<p>Hum, je vous vois sourciller.</p>
<p>Oui, c&#8217;est clair que la phrase est un peu tordue du cul, comme si elle avait été bottée.</p>
<p>Prenons donc un exemple : un service Web de bottage de cul !</p>
<p>Vous êtes donc asskicker.io, leader mondial du bottage de cul en ligne. Et vous exposez votre processus de bottage de cul exclusif à tous les programmeurs.</p>
<p>Pour ce faire, vous mettez à disposition une API WEB sous forme pseudo REST. Au lieu d&#8217;appeler des méthodes, les développeurs vont envoyer des requêtes HTTP Get et Post à des URLs représentant les culs à botter.</p>
<p>Je ne vais pas rentrer dans les détails de ce qu&#8217;est du (pseudo) REST ou JSON exactement, mais un exemple de requêtes à faire pour botter des culs via notre API Web serait :</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> json
<span style="color: #ff7700;font-weight:bold;">import</span> requests
&nbsp;
<span style="color: #808080; font-style: italic;"># On fait une requête GET vers l'URL du service pour obtenir de quoi s’énerver</span>
colere <span style="color: #66cc66;">=</span> requests.<span style="color: black;">get</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'http://asskicker.io/colere/'</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Je créer un nouveau bottage de cul</span>
data <span style="color: #66cc66;">=</span> json.<span style="color: black;">dumps</span><span style="color: black;">&#40;</span><span style="color: black;">&#123;</span><span style="color: #483d8b;">'cul'</span>: <span style="color: #483d8b;">'de bouteille'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'colere'</span>: colere<span style="color: black;">&#91;</span><span style="color: #483d8b;">'id'</span><span style="color: black;">&#93;</span><span style="color: black;">&#125;</span><span style="color: black;">&#41;</span>
headers <span style="color: #66cc66;">=</span> <span style="color: black;">&#123;</span><span style="color: #483d8b;">'content-type'</span>: <span style="color: #483d8b;">'application/json'</span><span style="color: black;">&#125;</span>
res <span style="color: #66cc66;">=</span> requests.<span style="color: black;">post</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'http://asskicker.io/bottage/'</span><span style="color: #66cc66;">,</span> data<span style="color: #66cc66;">=</span>data<span style="color: #66cc66;">,</span> headers<span style="color: #66cc66;">=</span>headers<span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Et supposons qu&#8217;on veuille connaître le dernier bottage de cul fait :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">res <span style="color: #66cc66;">=</span> requests.<span style="color: black;">get</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'http://asskicker.io/bottage/last'</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>res.<span style="color: black;">json</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;"># et la réponse JSON du service :</span>
<span style="color: #808080; font-style: italic;"># {</span>
<span style="color: #808080; font-style: italic;">#     &quot;bottage&quot;: 89080,</span>
<span style="color: #808080; font-style: italic;">#     &quot;cul&quot;: &quot;de bouteille&quot;,</span>
<span style="color: #808080; font-style: italic;">#     &quot;colere&quot;: 99943,</span>
<span style="color: #808080; font-style: italic;">#     &quot;date&quot;: &quot;2014-09-06 20:38:11&quot;</span>
<span style="color: #808080; font-style: italic;"># }</span></pre></td></tr></table></div>

<p>Les URLs sont fictives, complètement inventées, et ne correspondent à rien.</p>
<p>Ici, notre API est donc la collections d&#8217;URLs (<code>http://asskicker.io/bottage/</code>, <code>http://asskicker.io/bottage/last</code>, etc.) qui permet de manipuler notre service, ainsi que les nom set types des paramètres à envoyer via <code>data</code> et le contenu de la réponse.</p>
<p>Le but de l&#8217;API Web est de permettre de manipuler du code sur une machine distante à travers le Web, depuis n&#8217;importe quel langage capable d&#8217;envoyer une requête HTTP. L&#8217;API Twitter permet de de lister des tweets et en envoyer. Par exemple, si on est authentifié, faire une requête GET sur <a href="">http://api.twitter.com/1.1statuses/show/787998</a> permet d&#8217;obtenir en retour un JSON contenant les informations sur le tweet numéro 787998</p>
<p> L&#8217;API Google permet de faire des recherches. L&#8217;API flicker permet d&#8217;uploader des photos. Toutes les APIS ont des formes différentes, certaines sont plus ou moins faciles, plus ou moins efficaces, utilisent tels ou tels formats, mais au final, c&#8217;est la même chose : un moyen de manipuler le service en faisant des requêtes.</p>
<p>La manière classique de créer un site est de générer le HTML final sur le serveur. Or, comme il est possible d&#8217;envoyer des requêtes HTTP depuis une page Web en utilisant Ajax, on voit aujourd&#8217;hui des sites codés en Javascript qui vont chercher leurs données sur le serveur via l&#8217;API du site. Le navigateur reçoit ainsi un HTML incomplet, et le JS appelle l&#8217;API pour reconstruire la page.</p>
<p>Ainsi, on code la logique une seule fois : récupérer les informations, effectuer des actions&#8230; Et on utilise l&#8217;API pour tout ça, que ce soit pour faire le site Web, ou pour laisser d&#8217;autres programmeurs utiliser le site.</p>
<p>Évidemment, une vraie API Web est complexe, possède des problématiques de sécurité, d&#8217;authentification&#8230; Encore un bon article à écrire.</p>


feed_id: http://sametmax.com/?p=12170
title: AngularJS pour les utilisateurs de jQuery : partie 1
uri: AngularJS-pour-les-utilisateurs-de-jQuery-partie-1
url: http://sametmax.com/angularjs-pour-les-utilisateurs-de-jquery-partie-1/
content:
<p>Après avoir sondé un peu Twitter, le sujet intéresse, et il est très, mais alors, très mal traité ailleurs sur le net. Malgré mon aversion, <a href="http://sametmax.com/un-gros-troll-de-plus-sur-javacscript/">bien connue</a>, pour javascript, je m&#8217;en bouffe beaucoup, prog Web oblige.</p>
<p>Angular rend l&#8217;utilisation de JS plus supportable, mais possède une très grosse courbe d&#8217;apprentissage bien pentue, avec des ressources vraiment mal foutues.</p>
<p>Et surtout, le problème vient de l&#8217;habitude de jQuery.</p>
<p>AngularJS est l&#8217;anti-jQuery, ça ne fonctionne pas du tout pareil, mais personne n&#8217;est là pour vous montrer comment faire la transition. Ce sera le but de ce dossier, un dossier qui va être long car ce framework est un gros morceau.</p>
<h2>Quand utiliser AngularJS ?</h2>
<p>Tous les sites ne sont pas faits pour être créés avec Angular. En effet, si votre site est essentiellement composé de contenu statique, avec juste un peu de dynamique pour quelques widgets, Angular n&#8217;a aucun intérêt.</p>
<p>Angular est lourd à mettre en œuvre, on va donc se faire chier à sortir le bazooka quand on monte au front, pas quand on fait une garde de nuit en rase campagne.</p>
<p>Malgré le fait que Google interprète maintenant les pages en JS, le texte reste roi, et Angular vous force à faire des pages en pur JS, rendant le référencement aléatoire de votre contenu. Les hacks que l&#8217;on voit un peu partout sur la toile pour compenser cela sont très loin d&#8217;obtenir l&#8217;effet d&#8217;un référencement naturel de contenu facilement accessible à l&#8217;ancienne.</p>
<p>En fait, le plus gros défaut d&#8217;Angular, c&#8217;est qu&#8217;il ne permet pas, pour le moment, de faire de la dégradation gracieuse. Soit le mec a Javascript et il a accès au site. Soit le site est illisible.</p>
<p>jQuery a donc encore de beaux jours devant lui.</p>
<p>Typiquement, on ne prendra pas Angular pour :</p>
<ul>
<li>La partie publique d&#8217;un blog de type WordPress.</li>
<li>Un wiki type Wikipédia.</li>
<li>Un forum ou site collaboratif.</li>
<li>Un tube vidéo.</li>
</ul>
<p>Ce sont des sites dont le contenu est important. On veut que les moteurs de recherche puisse les indexer de fond en comble. On veut que ce soit lisible sans JS et par les aveugles (sauf le tube vidéo :-D). Les ajouts de JS se feront par petites touches.</p>
<p>On utilisera plutôt Angular pour :</p>
<ul>
<li>Une app grand public.</li>
<li>La partie admin d&#8217;un blog.</li>
<li>Un logiciel d&#8217;entreprise.</li>
<li>Un réseau social.</li>
</ul>
<p>Ce sont des sites pour lesquels l&#8217;ergonomie est plus importante que le contenu. Le public est captif, et on peut exiger Javascript, prix à payer pour une expérience utilisateur moderne.</p>
<p>Vous noterez qu&#8217;il y a une certaine opposition entre vieux format (wiki, forum, blog) et format contemporain (app, réseau social). Ce n&#8217;est pas un hasard. Les premiers sont orientés contenu, les seconds orientés usage. C&#8217;est ainsi que le Web a évolué, et Angular est là exactement pour répondre à cette évolution.</p>
<p>Il est néanmoins tout à fait possible de faire des choses hybrides. Rien n&#8217;empêche de faire des parties du sites statiques, et d&#8217;autres très dynamiques, de mélanger les deux sur une même page. Par exemple, sur un blog, vous pouvez mettre l&#8217;article en statique pour le ref et la facilité de consultation, et la partie commentaires en Angular, pour améliorer l&#8217;expérience utilisateur.</p>
<h2>Que va apporter Angular ?</h2>
<p>Les avantages sont doubles.</p>
<p>D&#8217;abords, il y a les avantages pour vous, le développeur. Angular vous force en effet à utiliser un style Javascript très propre qui tend à découpler les composants, isoler les services, lisser les angles et refaire le papier peint à fleur. L&#8217;application en devient plus propre, plus facile à faire évoluer et à maintenir. Toutes les bonnes pratiques d&#8217;organisation d&#8217;une app JS ont une réponse angularesque. Ce n&#8217;est pas forcément celle que vous voulez, mais elle marche.</p>
<p>Ensuite, Angular va vous rendre plus productif. Pas tout de suite, évidement, coincés que vous êtes dans votre logique jQuerinne. Mais une fois le cap passé, coder beaucoup de JS sera immensément plus simple et plus rapide, car Angular vous épargne beaucoup de logique répétitive.</p>
<p>En prime, ce framework est orienté tests. Ce n&#8217;est pas obligatoire, mais c&#8217;est bien plus facile qu&#8217;avec des modules jQuery.</p>
<p>Mais il y a également les avantages pour l&#8217;utilisateur. Puisque qu&#8217;Angular est complètement dynamique, il bénéficiera automatiquement d&#8217;une app plus réactive, avec moins de rechargements, plus de fonctionnalités aussi. En effet, vous rechignerez moins à rajouter cette fonction &#8220;delete-row&#8221; si vous savez que ça vous prend 3 lignes de code.</p>
<p>Attention cependant, il y a aussi des inconvénients.</p>
<p>Angular est lourd, c&#8217;est long à charger, ça bouffe de la ressource pour chaque tab, et si vous avez beaucoup de traitements sur une page, vous avez intérêt à optimiser votre race le bouzin sinon ça va ramer. Tout le monde n&#8217;est pas sur une machine de dev propre à 8 cœurs avec une ligne ADSL qui a tout compris.</p>
<p>En fait, si votre site est destiné à être consulté ainsi : je cherche, je consulte du contenu, et je m&#8217;en vais, charger Angular est un pur gâchis. Il faut au moins que l&#8217;on interagisse un peu avec le site pour que ça vaille le coup : créer du contenu, manipuler des informations, se faire notifier, etc.</p>
<p>Et puis il y a la tentation, la tentation forte de tout faire à la main côté client. Avec son lot de problèmes de sécurité (le delete qui fait pas de vérif), de merdier dans l&#8217;histo de navigation (le clic du milieu qui marche pas, le back qui back pas où on veut), les sessions qui font des siennes (je suis déco, mais y mon avartar là, pourquoi ?), etc.</p>
<p>Angular n&#8217;est pas une solution pour le bidouilleur Javascript de devenir soudainement grand programmeur Web, et ne dispense pas de coder correctement.</p>
<h2>Si je fais de l&#8217;Angular, je dois faire du NodeJS ?</h2>
<p>Non.</p>
<p>Angular est une techno parfaitement neutre, elle est limitée au client, et par conséquent, vous êtes libres de choisir votre techno côté serveur : .Net, PHP, Ruby, Java, Python&#8230;</p>
<p>Par contre, pour les tests, les outils sont très orientés autour de l&#8217;écosystème NodeJS : npm, grunt, PhantomJS, etc. Il va falloir mettre les mains dans le cambouis, avec son lot de trucs qui s&#8217;installent pas, de dépendances mal branlées, de doc pas à jour, de code JS peu expressif et tout le bordel. C&#8217;est tout le problème du JS, la communauté a gardé le côté crade et à l&#8217;arrache du langage. Heureusement, ils ont récupéré les designers du monde Ruby, donc vous aurez des tutos obsolètes, mais très jolis.</p>
<h2>Ok, mais je peux faire quoi avec ?</h2>
<p>Car finalement, quand on n&#8217;a pas utilisé Angular, on se demande finalement qu&#8217;est-ce que ça apporte par rapport à jQuery.</p>
<p>Essentiellement, c&#8217;est que ça divise par 100 les manipulations du DOM. Avec Angular, on met ses données dans un tableau d&#8217;objets JS, on indique où les afficher, et on manipule ensuite notre array. Le DOM est mis à jour sans qu&#8217;on doive s&#8217;en soucier.</p>
<p>Ça à l&#8217;air de rien comme ça, mais si vous ouvrez vos fichiers JS avec jQuery, vous verrez qu&#8217;ils sont blindés de <code>.click()</code>code et de <code>.append()</code>. C&#8217;est la majorité du code ! Code qu&#8217;on a pas besoin d&#8217;écrire avec Angular.</p>
<p>L&#8217;organisation d&#8217;Angular invite aussi naturellement à écrire un code linéaire. Pas de blocs dans des blocs dans des blocs, chaînes de callbacks et amas de closures. Il y en a toujours, mais bien moins.</p>
<p>Après, on fait finalement la même chose qu&#8217;on ferait avec jQuery, mais plus facilement. Ce qui explique qu&#8217;on fait rarement une app full JS avec jQuery, ce qui est infernal à coder, alors qu&#8217;on le fait systématiquement avec Angular, car c&#8217;est son milieu naturel.</p>
<p>Ce qui va vous surprendre avec cette façon de faire, c&#8217;est que tout ce qui s&#8217;affiche dans la page passe par Angular. En fait, on a généralement une API REST, et Angular en front pour afficher le site. Pas trop de templating côté serveur.</p>
<p>Et on verra des exemples concerts de tout ça dans les parties suivantes :)</p>


feed_id: http://sametmax.com/?p=12217
title: Le blog a été migré (enfin presque)
uri: Le-blog-a-été-migré-(enfin-presque)
url: http://sametmax.com/le-blog-a-ete-migre-enfin-presque/
content:
<p>Max a pris l&#8217;hébergement et a setup Varnish (sans lequel le WP s&#8217;écroule sous la masse de vos pattes velues), puis j&#8217;ai installé WP 4, et migré la DB et les images.</p>
<p>En gros, vous pouvez de nouveau lire vos articles techniques préférés. Et les autres aussi.</p>
<p>Par contre, feu notre ancien thème (snif, il était si&#8230; si&#8230; attachant&#8230;), et donc tous les easter eggs qui vont avec.</p>
<p>Vous noterez donc un blog moins fun, avec des bugs graphiques et surtout, sans plugins, donc ouvert aux 4 vents aux spams mais sans formulaire de contact. Mouarf.</p>
<p>Je vais corriger ça petit à petit, mais je ne me presse pas, l&#8217;avantage d&#8217;écrire un blog bénévole est qu&#8217;on ne doit rien à personne, donc on peut se gratter les couilles.</p>
<p>0bin, multiboards et allthatcount vont suivre. Je vais probablement les migrer avant de m&#8217;attaquer à la corrections des petits problèmes du blog d&#8217;ailleurs.</p>
<p>La base de données complète a été migrée. Félicitation à l&#8217;équipe de WP pour avoir mis en œuvre un outil de conversion des tables d&#8217;une version à l&#8217;autre parfaitement transparent. C&#8217;est pas facile à faire, et ça marche super bien. Mettez l&#8217;article en favoris, je ne dirais pas souvent du bien de cet outil.</p>
<p>Ça signifie que vos commentaires sont là, les pages statiques aussi, et bien entendu, pour les contributeurs, leurs comptes utilisateurs également. Il y a eu un bug de login ce matin, mais c&#8217;est réparé.</p>
<p>Si vous voyez des trucs qui pètent, merci de les lister en comment ici que je puisse avoir une check list à jour et sans doublons. Avec les URLS c&#8217;est mieux.</p>
<p>Parmi les problèmes que je vois venir : les iframes qui marchent pas, la barre de menu de droite qui déconne, et autres joyeusetés, des médias de mauvaise taille.</p>
<p>Et bonne lecture :)</p>


feed_id: http://sametmax.com/?p=12237
title: 0bin a été migré
uri: 0bin-a-été-migré
url: http://sametmax.com/0bin-a-ete-migre/
content:
<p>Vous vous souvenez de <a href="http://sametmax.com/0bin-implementation-python-de-zerobin-pastebin-chiffre-cote-client/">0bin, le paste bin chiffré</a> ? Il est de nouveau en ligne sur <a href="http://0bin.net/">0bin.net</a>.</p>
<p>Je suis en train de copier tous les pastes en ce moment, et il y en a  28436 donc rsync rame un peu (j&#8217;ai fait l&#8217;erreur de le faire avec scp au début&#8230;) du coup tous les pastes ne seront pas là instantanément, mais au final, on les retrouvera tous.</p>
<p>Bref, on répare doucement mais sûrement.</p>


feed_id: http://sametmax.com/?p=11783
title: Un bot qui tweete 4992 Super-Héros à raison de un toutes les 3,14 heures peut-il sauver Internet ?
uri: Un-bot-qui-tweete-4992-Super-Héros-à-raison-de-un-toutes-les-3-14-he
url:
http://sametmax.com/un-bot-qui-tweete-4992-super-heros-a-raison-de-un-toutes-les-314-heures-peut-il-sauver-internet/

content:
<p style="text-align: center;"><em><small>Ceci est un post invité de <a href="http://sametmax.com/author/01ivier/">01ivier</a> posté sous licence <a href="http://creativecommons.org/licenses/by/3.0/">creative common 3.0 unported</a>.</small></em></p>
<p>Depuis l&#8217;Antiquité, en moyenne, environ une seule personne s&#8217;est posée cette question, dont moi.</p>
<p>Je me propose donc de partager avec vous mon expérience sur le sujet en vous expliquant ce que j&#8217;ai mis en œuvre pour tenter d&#8217;obtenir une réponse.</p>
<h2>Bonsjours, je voudrais tweeter en Python, s&#8217;il vous plaît.</h2>
<p>Il existe plusieurs bibliothèques en Python qui papotent avec l&#8217;API de Twitter. <a href="https://dev.twitter.com/docs/twitter-libraries">Neuf sont actuellement référencées par Twitter</a>.</p>
<p>Parce qu&#8217;il y avait écrit &#8220;Actively maintained&#8221;, j&#8217;ai tenté <a href="https://github.com/ryanmcgrath/twython">twython</a> .</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> pip <span style="color: #c20cb9; font-weight: bold;">install</span> twython</pre></td></tr></table></div>

<p>Il se trouve qu&#8217;elle fait très bien ce que j&#8217;attendais d&#8217;elle, donc je ne suis pas allé chercher plus loin.</p>
<p>Par ailleurs, le code pour envoyer un tweet est flippant de simplicité :</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> twython <span style="color: #ff7700;font-weight:bold;">import</span> Twython
&nbsp;
APP_KEY <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;votre petite clef-clef à vous&quot;</span>
APP_SECRET <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;une autre petite clef-clef&quot;</span>
OAUTH_TOKEN <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;encore une petite clef-clef&quot;</span>
OAUTH_TOKEN_SECRET <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;enfin, une dernière petite clef-clef&quot;</span>
&nbsp;
twitter <span style="color: #66cc66;">=</span> Twython<span style="color: black;">&#40;</span>APP_KEY<span style="color: #66cc66;">,</span> APP_SECRET<span style="color: #66cc66;">,</span> OAUTH_TOKEN<span style="color: #66cc66;">,</span> OAUTH_TOKEN_SECRET<span style="color: black;">&#41;</span>
&nbsp;
texte <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">'Oh mon Dieu ! Mais cette librairie crache des flammes ! #Twython'</span>
&nbsp;
twitter.<span style="color: black;">update_status</span><span style="color: black;">&#40;</span>status<span style="color: #66cc66;">=</span>texte<span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Et paf :</p>
<blockquote class="twitter-tweet" lang="fr"><p>Oh mon Dieu ! Mais cette librairie crache des flammes ! <a href="https://twitter.com/hashtag/Twython?src=hash">#Twython</a></p>
<p>— AllStarsNetSupaHeros (@4992SuperHeros) <a href="https://twitter.com/1881SuperHeros/statuses/499002145862320128">12 Août 2014</a></p></blockquote>
<p>&nbsp;</p>
<p>Pour obtenir ses <em>petites clefs-clefs</em>, il est nécessaire de se créer un compte sur <a href="http://dev.twitter.com/">la plate-forme de Twitter réservée aux développeurs</a>.</p>
<p>Je vous la fait courte :</p>
<p>&gt; <em>My applications</em> dans le menu de votre icône en haut à droite &gt; <em>Create New Apps</em><br />
&gt; Remplir le formulaire &gt; accepter les conditions d&#8217;utilisation <a href="http://www.legorafi.fr/2014/07/15/ivre-elle-lit-lintegralite-des-conditions-dutilisation-ditunes/">après les avoir lues</a><br />
&gt; <em>Permissions</em> &gt; <em>Read and Write</em><br />
&gt; <em>API Keys</em> &gt; <em>Generate my acces token</em></p>
<p>La partie la plus compliquée pour moi fut de passer les permissions en &#8220;<strong>Read and Write</strong>&#8220;.</p>
<p>En effet, il faut <strong>associer un numéro de téléphone au compte twitter</strong> utilisé et la manipulation doit être faite à partir du téléphone en question.<br />
Or, je n&#8217;ai pas de téléphone portable.</p>
<p>Heureusement, la femme de ma <strong>Vie</strong> a eu la bonne idée de faire l&#8217;<strong>Amour</strong> il y a 17 ans et sa fille, la fille de ma <strong>Vie</strong>, possède ce genre d&#8217;appareil.<br />
Sauvé.</p>
<p>Si vous n&#8217;avez pas de fille de votre <strong>Vie</strong>, ni même de femme de votre <strong>Vie</strong>, faites en sorte d&#8217;avoir un téléphone portable.</p>
<p>(J&#8217;ai mis <strong>Amour</strong> et <strong>Vie</strong> en gras pour gagner des points de Karma. Je ne sais pas si ça marche, mais je me dis que ce serait tout de même bien malheureux que ça ait un effet négatif.)</p>
<h2>Bonsjours, je voudrais ajouter une image au tweet que je tweete en Python, s&#8217;il vous plaît.</h2>
<p>En partant du principe que vous avez une <em>image.png</em> à côté de votre script :</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> twython <span style="color: #ff7700;font-weight:bold;">import</span> Twython
&nbsp;
APP_KEY <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;votre petite clef-clef à vous&quot;</span>
APP_SECRET <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;une autre petite clef-clef&quot;</span>
OAUTH_TOKEN <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;encore une petite clef-clef&quot;</span>
OAUTH_TOKEN_SECRET <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;enfin, une dernière petite clef-clef&quot;</span>
&nbsp;
twitter <span style="color: #66cc66;">=</span> Twython<span style="color: black;">&#40;</span>APP_KEY<span style="color: #66cc66;">,</span> APP_SECRET<span style="color: #66cc66;">,</span> OAUTH_TOKEN<span style="color: #66cc66;">,</span> OAUTH_TOKEN_SECRET<span style="color: black;">&#41;</span>
&nbsp;
texte <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">'Mais quelle folie ! #Twython tweete aussi des images ! '</span>
image <span style="color: #66cc66;">=</span> <span style="color: #008000;">open</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;image.png&quot;</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'rb'</span><span style="color: black;">&#41;</span>
&nbsp;
twitter.<span style="color: black;">update_status_with_media</span><span style="color: black;">&#40;</span>status<span style="color: #66cc66;">=</span>texte<span style="color: #66cc66;">,</span> media<span style="color: #66cc66;">=</span>image<span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Et hop :</p>
<blockquote class="twitter-tweet" lang="fr"><p>Mais quelle folie ! <a href="https://twitter.com/hashtag/Twython?src=hash">#Twython</a> tweete aussi des images ! <a href="http://t.co/1sK9RH2qdP">pic.twitter.com/1sK9RH2qdP</a></p>
<p>— AllStarsNetSupaHeros (@4992SuperHeros) <a href="https://twitter.com/1881SuperHeros/statuses/499003722715103232">12 Août 2014</a></p></blockquote>
<p>&nbsp;</p>
<p>J&#8217;ai du mal à imaginer qu&#8217;on puisse faire plus simple.</p>
<h2>Maintenant, j&#8217;aimerais tweeter toutes les 3,14 heures. C&#8217;est possible ?</h2>
<p>Pour tweeter toutes les 3 heures, une petite <a href="http://fr.wikipedia.org/wiki/Crontab">crontab</a> réglée de la sorte aurait fait l&#8217;affaire :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #000000;">0</span> <span style="color: #000000; font-weight: bold;">*/</span><span style="color: #000000;">3</span> <span style="color: #000000; font-weight: bold;">*</span> <span style="color: #000000; font-weight: bold;">*</span> <span style="color: #000000; font-weight: bold;">*</span> python chemin<span style="color: #000000; font-weight: bold;">/</span>vers<span style="color: #000000; font-weight: bold;">/</span>mon<span style="color: #000000; font-weight: bold;">/</span>script.py</pre></td></tr></table></div>

<p>Mais pour 3,14 heures, il faut faire dans le délicat.<br />
Je fais donc patienter le script 11 304 secondes entre chaque envoi :</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;">time</span> <span style="color: #ff7700;font-weight:bold;">import</span> sleep
&nbsp;
<span style="color: #ff7700;font-weight:bold;">while</span> <span style="color: #008000;">True</span>:
&nbsp;
	envoie_moi_donc_un_tweet_avec_une_image_de_Super_Heros_du_Net<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
	sleep<span style="color: black;">&#40;</span><span style="color: #ff4500;">11304</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Tout à fait cochon.<br />
Tout à fait parfait.</p>
<h2>Et pour les 4992 Super-Héros.<br />
Comment fait-on ?</h2>
<p>Alors là, vous n&#8217;allez pas être déçus.</p>
<p>Afin de d&#8217;obtenir 4992 Super-Héros, je me suis dit qu&#8217;il me suffisait de trouver 24 têtes de Super-Héros, 13 torses de Super-Héros et 16 jambes de Super-Héros puis de réaliser toutes les combinaisons possibles de ces trois éléments.</p>
<p>24 * 13 * 16 = <strong>4992</strong></p>
<p>Hasard de folie, il se trouve qu&#8217;afin de récolter des fonds pour mener à bien leurs actions, <a href="https://www.laquadrature.net/fr">La Quadrature Du Net</a> propose une petite appli de personnalisation de Super-Héros pour celles et ceux qui <a href="http://soutien.laquadrature.net/">font un don</a>.</p>
<p><a href="http://sametmax.com/ou-il-est-presente-une-methode-en-python-pour-afficher-de-la-video-3-bit-dans-son-terminal/interface_quadrature-3/" rel="attachment wp-att-11841"><img class="aligncenter size-full wp-image-11841" title="interface_quadrature" src="media/e712ea44.interface_quadrature1.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/06/interface_quadrature1.png" alt="" width="600" height="368" /></a></p>
<p>Et bien, aussi incroyable que cela puisse paraître, elle propose de choisir parmi 24 têtes de Super-Héros du Net, 13 torses de Super-Héros du Net, 16 jambes de Super-Héros du Net.</p>
<p>L&#8217;émotion est un peu retombée, mais, sur le moment, j&#8217;ai eu la chaire de poule face à une telle coïncidence, surtout quand on sait que La Quadrature <strong>défend les droits et les libertés des citoyens sur Internet</strong> depuis 2008 et que c&#8217;est pile-poil dans la thématique de la question qui fait l&#8217;objet de cet article.</p>
<p>Me voilà donc parti pour trouver un moyen de récupérer tous ces morceaux de Super-Héros du Net et de reconstituer les 4992 Super-Héros entiers possibles.</p>
<p>Pour retrouver l&#8217;adresse de chaque morceau, un simple coup d’œil au code-source de la page a suffi.</p>
<p><a href="http://sametmax.com/un-bot-qui-tweete-4992-super-heros-a-raison-de-un-toutes-les-314-heures-peut-il-sauver-internet/source_1881/" rel="attachment wp-att-11928"><img class="aligncenter size-full wp-image-11928" title="source_4992" src="media/b32dc5b2.source_1881.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/08/source_1881.png" alt="" width="600" height="541" /></a></p>
<p>Ensuite, en terme de n&#8217;importe quoi je vous propose un morceau de choix.</p>
<p>Car pour faire ma petite popote, j&#8217;ai utilisé <a href="http://processing.org/">Processing</a>.</p>
<p>_ Processing ?!?!<br />
_ Oui. Processing.<br />
_ Mais&#8230; ça utilise une syntaxe Java, ça. Non ?<br />
_ Oui. Mais pour Sam&amp;Max j&#8217;ai utilisé <a href="https://github.com/jdf/processing.py">le mode Python qui vient tout juste de sortir</a>.<br />
_ Utiliser un &#8220;framework Java&#8221; en Python. Excuse-moi, mais c&#8217;est un peu n&#8217;importe quoi.<br />
_ Tout à fait.</p>
<p>Pour celles et ceux qui ne le connaissent pas, Processing est un logiciel/langage conçu pour que les artistes, les graphistes, les designers et les grosses bubuses comme moi puissent facilement et rapidement produire du code créatif (image, son, vidéo).</p>
<p>Je ne vais pas vous faire un cours. Il y a un <a href="http://fr.flossmanuals.net/processing/">FLOSS Manual en français</a> pour ça.</p>
<p>Utilisant Processing depuis plusieurs années, je vous avoue que le mode Python m&#8217;a clairement donné l&#8217;impression de faire du skate avec des rollers, mais comme outils pédagogique, ça doit être pas mal.<br />
Et puis ça marche !</p>
<p>Voici le code que j&#8217;ai pondu pour l&#8217;occasion :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># La fonction setup() est propre à Processing.</span>
<span style="color: #808080; font-style: italic;"># Elle s’exécute en premier et une seule fois.</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> setup<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
&nbsp;
    <span style="color: #808080; font-style: italic;"># On crée une image transparente de 1 pixel de côté qui sera utilisée</span>
    <span style="color: #808080; font-style: italic;"># pour représenter l’absence de choix de tête, de torse et de jambes</span>
    img_vide <span style="color: #66cc66;">=</span> createImage<span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">1</span><span style="color: #66cc66;">,</span> ARGB<span style="color: black;">&#41;</span>
    img_vide.<span style="color: black;">pixels</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span> <span style="color: #66cc66;">=</span> color<span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># On crée des listes qui contiendront les images des têtes, torses et jambes</span>
    <span style="color: #808080; font-style: italic;"># et on place l'image vide crée juste avant comme premier élément.</span>
    <span style="color: #ff7700;font-weight:bold;">global</span> liste_torses<span style="color: #66cc66;">,</span> liste_tetes<span style="color: #66cc66;">,</span> liste_jambes
    liste_tetes <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span>img_vide<span style="color: black;">&#93;</span>
    liste_torses <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span>img_vide<span style="color: black;">&#93;</span>
    liste_jambes <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span>img_vide<span style="color: black;">&#93;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># On lance le téléchargement de toutes les images nécessaires.</span>
    telechargement_images<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># On fabrique les 4992 Super-Héros avec les images téléchargées.</span>
    usine_super_heros<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> telechargement_images<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
&nbsp;
    <span style="color: #808080; font-style: italic;"># Sachant que chaque image est atteignable par une URL du type</span>
    <span style="color: #808080; font-style: italic;"># http://soutien.laquadrature.net/images/bonus/head_01.png</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># On définit l'URL du dossier où sont situées les images.</span>
    url <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;http://soutien.laquadrature.net/images/bonus/&quot;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># On télécharge l'image du Super-Héros tout nu qui est placé au fond</span>
    <span style="color: #808080; font-style: italic;"># de chaque image et qui sert de base à tous les autres.</span>
    <span style="color: #ff7700;font-weight:bold;">global</span> base
    base <span style="color: #66cc66;">=</span> loadImage<span style="color: black;">&#40;</span>url + <span style="color: #483d8b;">&quot;base.png&quot;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># On télécharge les 24 têtes, les 13 torses et les 16 jambes.</span>
    choix_image<span style="color: black;">&#40;</span>url<span style="color: #66cc66;">,</span> <span style="color: #483d8b;">&quot;head_&quot;</span><span style="color: #66cc66;">,</span> liste_tetes<span style="color: #66cc66;">,</span> <span style="color: #ff4500;">24</span><span style="color: black;">&#41;</span>
    choix_image<span style="color: black;">&#40;</span>url<span style="color: #66cc66;">,</span> <span style="color: #483d8b;">&quot;torso_&quot;</span><span style="color: #66cc66;">,</span> liste_torses<span style="color: #66cc66;">,</span> <span style="color: #ff4500;">13</span><span style="color: black;">&#41;</span>
    choix_image<span style="color: black;">&#40;</span>url<span style="color: #66cc66;">,</span> <span style="color: #483d8b;">&quot;legs_&quot;</span><span style="color: #66cc66;">,</span> liste_jambes<span style="color: #66cc66;">,</span> <span style="color: #ff4500;">16</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> choix_image<span style="color: black;">&#40;</span>url<span style="color: #66cc66;">,</span> nom<span style="color: #66cc66;">,</span> liste<span style="color: #66cc66;">,</span> nb_image<span style="color: black;">&#41;</span>:
&nbsp;
    <span style="color: #808080; font-style: italic;"># Pour chaque nombre entre 1 et nb_image (0 correspondant à img_vide),</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> nb_image<span style="color: black;">&#41;</span>:
&nbsp;
        <span style="color: #808080; font-style: italic;"># on définit un numéro toujours composé de 2 chiffres. Ex: 05 pour 5,</span>
        numero <span style="color: #66cc66;">=</span> <span style="color: #008000;">str</span><span style="color: black;">&#40;</span>i<span style="color: black;">&#41;</span>.<span style="color: black;">zfill</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span>
        <span style="color: #808080; font-style: italic;"># on récupère l'image en recomposant l'URL,</span>
        image_recuperee <span style="color: #66cc66;">=</span> loadImage<span style="color: black;">&#40;</span>url + nom + numero + <span style="color: #483d8b;">&quot;.png&quot;</span><span style="color: black;">&#41;</span>
        <span style="color: #808080; font-style: italic;"># et on ajoute cette image dans la liste correspondante.</span>
        liste.<span style="color: black;">append</span><span style="color: black;">&#40;</span>image_recuperee<span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> usine_super_heros<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
&nbsp;
    <span style="color: #808080; font-style: italic;"># Sachant que toutes images récupérées ont la même taille (214x383)</span>
    <span style="color: #808080; font-style: italic;"># et qu'elles sont des .png transparents dont le contenu trouve sa place</span>
    <span style="color: #808080; font-style: italic;"># quand les images sont parfaitement superposées .</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># On définit une variable qui va compter les 4992 Super-Héros.</span>
    compteur <span style="color: #66cc66;">=</span> <span style="color: #ff4500;">0</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Pour toutes les images de têtes,</span>
    <span style="color: #ff7700;font-weight:bold;">for</span> tete <span style="color: #ff7700;font-weight:bold;">in</span> liste_tetes:
&nbsp;
        <span style="color: #808080; font-style: italic;"># pour toutes les images de torses,</span>
        <span style="color: #ff7700;font-weight:bold;">for</span> torse <span style="color: #ff7700;font-weight:bold;">in</span> liste_torses:
&nbsp;
            <span style="color: #808080; font-style: italic;"># et pour toutes les images de jambes,</span>
            <span style="color: #ff7700;font-weight:bold;">for</span> jambe <span style="color: #ff7700;font-weight:bold;">in</span> liste_jambes:
&nbsp;
                <span style="color: #808080; font-style: italic;"># on crée un élément graphique de 214x383,</span>
                super_hero <span style="color: #66cc66;">=</span> createGraphics<span style="color: black;">&#40;</span><span style="color: #ff4500;">214</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">383</span><span style="color: black;">&#41;</span>
                <span style="color: #808080; font-style: italic;"># on démarre le dessin de l'élément graphique,</span>
                super_hero.<span style="color: black;">beginDraw</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
                <span style="color: #808080; font-style: italic;"># on place un fond blanc,</span>
                super_hero.<span style="color: black;">background</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">255</span><span style="color: black;">&#41;</span>
                <span style="color: #808080; font-style: italic;"># on place le Super-Héros tout nu aux coordonnées 0, 0</span>
                super_hero.<span style="color: black;">image</span><span style="color: black;">&#40;</span>base<span style="color: #66cc66;">,</span> <span style="color: #ff4500;">0</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>
                <span style="color: #808080; font-style: italic;"># on place l'image des jambes en 0, 0</span>
                super_hero.<span style="color: black;">image</span><span style="color: black;">&#40;</span>jambe<span style="color: #66cc66;">,</span> <span style="color: #ff4500;">0</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>
                <span style="color: #808080; font-style: italic;"># on place l'image du torse en 0, 0</span>
                super_hero.<span style="color: black;">image</span><span style="color: black;">&#40;</span>torse<span style="color: #66cc66;">,</span> <span style="color: #ff4500;">0</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>
                <span style="color: #808080; font-style: italic;"># on place l'image de la tête en 0, 0</span>
                super_hero.<span style="color: black;">image</span><span style="color: black;">&#40;</span>tete<span style="color: #66cc66;">,</span> <span style="color: #ff4500;">0</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>
                <span style="color: #808080; font-style: italic;"># on clos le dessin de l'élément graphique,</span>
                super_hero.<span style="color: black;">endDraw</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
                <span style="color: #808080; font-style: italic;"># on sauvegarde notre Super-Héros du Net dans le dossier data,</span>
                super_hero.<span style="color: black;">save</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;data/SuperHeros-{0}.png&quot;</span>.<span style="color: black;">format</span><span style="color: black;">&#40;</span>compteur<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
                <span style="color: #808080; font-style: italic;"># et on incrémente le compteur de 1 avant de passer</span>
                <span style="color: #808080; font-style: italic;"># au Super-Héros suivant</span>
                compteur +<span style="color: #66cc66;">=</span> <span style="color: #ff4500;">1</span></pre></td></tr></table></div>

<p>Et hop !</p>
<p><a href="http://sametmax.com/un-bot-qui-tweete-4992-super-heros-a-raison-de-un-toutes-les-314-heures-peut-il-sauver-internet/allstar/" rel="attachment wp-att-12001"><img class="aligncenter size-full wp-image-12001" title="AllStar" src="media/63e1bf3f.AllStar.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/08/AllStar.png" alt="" width="600" height="500" /></a></p>
<h2>Et sinon, c&#8217;est encore loin Grand Schtroumpf ?</h2>
<p>On arrive au bout.</p>
<p>Pour ne pas tweeter les Super-Héros du Net dans l&#8217;ordre et pour ne pas non plus poster deux fois le même en cas de croutage du serveur, je me suis créé un petit <em>ordre.txt</em> comme cela :</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;">random</span> <span style="color: #ff7700;font-weight:bold;">import</span> shuffle
&nbsp;
tous_les_numeros <span style="color: #66cc66;">=</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">4992</span><span style="color: black;">&#41;</span>
shuffle<span style="color: black;">&#40;</span>tous_les_numeros<span style="color: black;">&#41;</span>
&nbsp;
<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;">&quot;ordre.txt&quot;</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> base:
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">for</span> numero <span style="color: #ff7700;font-weight:bold;">in</span> tous_les_numeros:
&nbsp;
        base.<span style="color: black;">write</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;{0},&quot;</span>.<span style="color: black;">format</span><span style="color: black;">&#40;</span>numero<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Et dont le contenu est juste :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #000000;">1798</span>,<span style="color: #000000;">915</span>,<span style="color: #000000;">1402</span>,<span style="color: #000000;">1032</span>,<span style="color: #000000;">507</span>,<span style="color: #000000;">112</span>,<span style="color: #000000;">1098</span>,<span style="color: #000000;">600</span>,<span style="color: #000000;">323</span>,<span style="color: #000000;">787</span>,<span style="color: #000000;">1435</span>,<span style="color: #000000;">200</span>,<span style="color: #000000;">774</span>,<span style="color: #000000;">33</span>,<span style="color: #000000;">1419</span>,<span style="color: #000000;">106</span>,<span style="color: #000000;">1836</span>... etc</pre></td></tr></table></div>

<p>Enfin, voici le script final, qui tweete donc toutes les 3,14 heures un des 4992 Super-Héros du Net.</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: utf8 -*-</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Ce script permet d'envoyer un tweet avec une image toutes les 3,14 heures</span>
<span style="color: #808080; font-style: italic;"># Il récupère dans une liste le numéro de l'image a envoyer,</span>
<span style="color: #808080; font-style: italic;"># et enregistre le nombre de tweets déjà postés</span>
<span style="color: #808080; font-style: italic;"># pour pouvoir changer d'image à la prochaine exécution</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">os</span>
<span style="color: #ff7700;font-weight:bold;">from</span> twython <span style="color: #ff7700;font-weight:bold;">import</span> Twython
<span style="color: #ff7700;font-weight:bold;">from</span> <span style="color: #dc143c;">time</span> <span style="color: #ff7700;font-weight:bold;">import</span> sleep
&nbsp;
<span style="color: #808080; font-style: italic;"># Clef d'authentification à obtenir sur https://dev.twitter.com</span>
APP_KEY <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;votre petite clef-clef à vous&quot;</span>
APP_SECRET <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;une autre petite clef-clef&quot;</span>
OAUTH_TOKEN <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;encore une petite clef-clef&quot;</span>
OAUTH_TOKEN_SECRET <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;enfin, une dernière petite clef-clef&quot;</span>
&nbsp;
twitter <span style="color: #66cc66;">=</span> Twython<span style="color: black;">&#40;</span>APP_KEY<span style="color: #66cc66;">,</span> APP_SECRET<span style="color: #66cc66;">,</span> OAUTH_TOKEN<span style="color: #66cc66;">,</span> OAUTH_TOKEN_SECRET<span style="color: black;">&#41;</span>
&nbsp;
ordre <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>
combien_deja_poste <span style="color: #66cc66;">=</span> <span style="color: #ff4500;">0</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Récupère le répertoire courant</span>
chemin_dossier <span style="color: #66cc66;">=</span> <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">dirname</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">realpath</span><span style="color: black;">&#40;</span>__file__<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>+<span style="color: #483d8b;">&quot;/&quot;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> envoie_moi_donc_un_tweet_avec_une_image_de_Super_Heros_du_Net<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
&nbsp;
    <span style="color: #808080; font-style: italic;"># Récupère l'ordre des images à poster</span>
    <span style="color: #ff7700;font-weight:bold;">with</span> <span style="color: #008000;">open</span> <span style="color: black;">&#40;</span>chemin_dossier+<span style="color: #483d8b;">&quot;ordre.txt&quot;</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'r'</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">as</span> contenu:
&nbsp;
            ordre <span style="color: #66cc66;">=</span> contenu.<span style="color: #dc143c;">readline</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>.<span style="color: black;">rstrip</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'<span style="color: #000099; font-weight: bold;">\n</span>'</span><span style="color: black;">&#41;</span>.<span style="color: black;">split</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;,&quot;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Récupère le nombre d'images déjà postées</span>
    <span style="color: #ff7700;font-weight:bold;">with</span> <span style="color: #008000;">open</span> <span style="color: black;">&#40;</span>chemin_dossier+<span style="color: #483d8b;">&quot;deja_poste.txt&quot;</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'r'</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">as</span> contenu:
&nbsp;
        combien_deja_poste <span style="color: #66cc66;">=</span> <span style="color: #008000;">int</span><span style="color: black;">&#40;</span>contenu.<span style="color: #dc143c;">readline</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>.<span style="color: black;">rstrip</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'<span style="color: #000099; font-weight: bold;">\n</span><span style="color: #000099; font-weight: bold;">\r</span>'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Récupère le numéro de l'image</span>
    numero <span style="color: #66cc66;">=</span> <span style="color: #008000;">int</span><span style="color: black;">&#40;</span>ordre<span style="color: black;">&#91;</span>combien_deja_poste<span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Construit le chemin vers cette image</span>
    <span style="color: #808080; font-style: italic;"># Sachant que le dossier AllStar contient les 4992 Super-Héros du Net</span>
    chemin_image <span style="color: #66cc66;">=</span> chemin_dossier+<span style="color: #483d8b;">&quot;AllStar/SuperHeros-{0}.png&quot;</span>.<span style="color: black;">format</span><span style="color: black;">&#40;</span>numero<span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Charge l'image</span>
    image <span style="color: #66cc66;">=</span> <span style="color: #008000;">open</span><span style="color: black;">&#40;</span>chemin_image<span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'rb'</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Forme le texte du tweet</span>
    texte <span style="color: #66cc66;">=</span> <span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Voici le Super-Héros du Net n°{0}<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span>
             <span style="color: #483d8b;">&quot;Si ce n'est pas déjà fait, aidez-le, lui et ses 4992 amis<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span>
             <span style="color: #483d8b;">&quot;soutien.laquadrature.net&quot;</span><span style="color: black;">&#41;</span>.<span style="color: black;">format</span><span style="color: black;">&#40;</span>numero+<span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Envoie le tweet composé d'un texte et d'une image</span>
    twitter.<span style="color: black;">update_status_with_media</span><span style="color: black;">&#40;</span>status<span style="color: #66cc66;">=</span>texte<span style="color: #66cc66;">,</span> media<span style="color: #66cc66;">=</span>image<span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Met à jour le nombre d'images déjà postées</span>
    <span style="color: #ff7700;font-weight:bold;">with</span> <span style="color: #008000;">open</span> <span style="color: black;">&#40;</span>chemin_dossier+<span style="color: #483d8b;">&quot;deja_poste.txt&quot;</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> contenu:
&nbsp;
        contenu.<span style="color: black;">write</span><span style="color: black;">&#40;</span><span style="color: #008000;">str</span><span style="color: black;">&#40;</span>combien_deja_poste + <span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">while</span> <span style="color: #008000;">True</span>:
&nbsp;
    envoie_moi_donc_un_tweet_avec_une_image_de_Super_Heros_du_Net<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Patiente pendant les 3,14 heures, soit  les 11 304 secondes</span>
    sleep<span style="color: black;">&#40;</span><span style="color: #ff4500;">11304</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Le script plantera dans 2 ans quand les 4992 Super-Héros du Net</span>
    <span style="color: #808080; font-style: italic;"># aurons tous été postés, et c'est très bien ainsi...</span></pre></td></tr></table></div>

<p>Et voilà, il ne reste plus qu&#8217;à choper 10 Millions de followers sur <a href="https://twitter.com/4992SuperHeros">ce compte</a> et à espérer que 3,14% d&#8217;entre eux filent 10€ à LQDN pour que l&#8217;on puisse augmenter les chances de répondre positivement à la question posée dans le titre.<br />
Une simple formalité&#8230;</p>
<p>Je précise que La Quadrature n&#8217;a absolument rien à voir avec ce compte Twitter, c&#8217;était juste l&#8217;occasion pour moi de pondre un article de plus ici tout en soutenant une cause qui me tient hackeur (humour).</p>
<p>À la prochaine&#8230;</p>
<p><em>Information complémentaire : </em><br />
Le Monde en date du 12 août &#8211; <a href="http://www.lemonde.fr/economie/article/2014/08/12/pres-d-un-compte-twitter-sur-10-est-alimente-par-un-robot_4470542_3234.html?xtmc=robot_twitter&amp;xtcr=1">Près d&#8217;un compte Twitter sur 10 est alimenté automatiquement</a></p>


feed_id: http://sametmax.com/?p=12261
title: Trouver ce qui prend de la place en ligne de commande
uri: Trouver-ce-qui-prend-de-la-place-en-ligne-de-commande
url: http://sametmax.com/trouver-ce-qui-prend-de-la-place-en-ligne-de-commande/
content:
<p>Windows a l&#8217;excellent WindDirStats, et Gnome a Baobab. Mais régulièrement je suis en SSH sur un server je lance <code>df</code> pour voir comment vont les disques. La vérité c&#8217;est que ceux avec un monitoring installés ne sont pas la majorité dans mes missions.</p>
<p>À un moment ou un autre, une partition est pleine. Et une fois qu&#8217;on a vidé <code>/var/log</code> et que le taux de remplissage ne semble pas baisser, il faut enquêter.</p>
<p>En général, je recherche sur le net une incantation magique du genre :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># trouver les fichiers qui prennent le plus de place</span>
<span style="color: #c20cb9; font-weight: bold;">find</span> . <span style="color: #660033;">-type</span> f <span style="color: #660033;">-print0</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">xargs</span> <span style="color: #660033;">-0</span> <span style="color: #c20cb9; font-weight: bold;">du</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">sort</span> <span style="color: #660033;">-n</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">tail</span> <span style="color: #660033;">-10</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">cut</span> <span style="color: #660033;">-f2</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">xargs</span> -I<span style="color: #7a0874; font-weight: bold;">&#123;</span><span style="color: #7a0874; font-weight: bold;">&#125;</span> <span style="color: #c20cb9; font-weight: bold;">du</span> <span style="color: #660033;">-sh</span> <span style="color: #7a0874; font-weight: bold;">&#123;</span><span style="color: #7a0874; font-weight: bold;">&#125;</span>
<span style="color: #666666; font-style: italic;"># trouver les dossiers qui prennent le plus de place</span>
<span style="color: #c20cb9; font-weight: bold;">find</span> . <span style="color: #660033;">-type</span> d <span style="color: #660033;">-print0</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">xargs</span> <span style="color: #660033;">-0</span> <span style="color: #c20cb9; font-weight: bold;">du</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">sort</span> <span style="color: #660033;">-n</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">tail</span> <span style="color: #660033;">-10</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">cut</span> <span style="color: #660033;">-f2</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">xargs</span> -I<span style="color: #7a0874; font-weight: bold;">&#123;</span><span style="color: #7a0874; font-weight: bold;">&#125;</span> <span style="color: #c20cb9; font-weight: bold;">du</span> <span style="color: #660033;">-sh</span> <span style="color: #7a0874; font-weight: bold;">&#123;</span><span style="color: #7a0874; font-weight: bold;">&#125;</span></pre></td></tr></table></div>

<p>Puis je me souviens qu&#8217;il y a <code>du</code>, alors je commence à faire un truc comme ça :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">du</span> <span style="color: #660033;">-a</span> . <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">sort</span> <span style="color: #660033;">-n</span> <span style="color: #660033;">-r</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">head</span> <span style="color: #660033;">-n</span> <span style="color: #000000;">10</span></pre></td></tr></table></div>

<p>Mais un jour je suis tombé sur un post d&#8217;un forum disant que je me cassais les couilles pour rien, et qu&#8217;utiliser <code>ncdu</code> était plus simple. Sous Ubuntu :</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> ncdu
ncdu</pre></td></tr></table></div>

<p>Et effectivement, je me cassais les couilles pour rien, c&#8217;est plus simple.</p>


feed_id: http://sametmax.com/?p=12251
title: Accélérer les listings de l’admin Django avec beaucoup de ForeignKeys
uri: Accélérer-les-listings-de-l-admin-Django-avec-beaucoup-de-ForeignK
url: http://sametmax.com/accelerer-les-listings-de-ladmin-django-avec-beaucoup-de-foreignkeys/
content:
<p>Je pensais que ces astuces étaient très connues, mais quand j&#8217;en ai eu besoin, j&#8217;ai galéré pour mettre la main dessus. Du coup blogage, blogation, blogitude.</p>
<p>L&#8217;admin Django permet de faire automatiquement un listing des objets voulus afin de les modifier. Si un modèle a une ForeignKey et qu&#8217;on définit le champ en <code>list_editable</code>, Django va pondre un drop down pour choisir parmi les relations possibles.</p>
<p>Or, le framework fait une requête <strong>pour chaque objet de la liste</strong>. Si vous avez deux ForeignKeys sur votre modèle et 20 objets (valeur par défaut) dans la liste, ça vous fait donc 40 queries, juste pour afficher ces deux drop down. Doh.</p>
<p>On peut néanmoins forcer Django à cacher le résultat de la première requête, réduisant ainsi le compte à 1, avec cette étrange astuce d&#8217;une mère au foyer (consultants hate her !) :</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> VotreClasseAdmin<span style="color: black;">&#40;</span>admin.<span style="color: black;">ModelAdmin</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Cette méthode est appelée pour créer le champ de formulaire de pour</span>
    <span style="color: #808080; font-style: italic;"># chaque objet</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> formfield_for_dbfield<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: #66cc66;">,</span> db_field<span style="color: #66cc66;">,</span> **kwargs<span style="color: black;">&#41;</span>:
&nbsp;
        request <span style="color: #66cc66;">=</span> kwargs<span style="color: black;">&#91;</span><span style="color: #483d8b;">'request'</span><span style="color: black;">&#93;</span>
        formfield <span style="color: #66cc66;">=</span> <span style="color: #008000;">super</span><span style="color: black;">&#40;</span>ProductPageAdmin<span style="color: #66cc66;">,</span> <span style="color: #008000;">self</span><span style="color: black;">&#41;</span>.<span style="color: black;">formfield_for_dbfield</span><span style="color: black;">&#40;</span>db_field<span style="color: #66cc66;">,</span> **kwargs<span style="color: black;">&#41;</span>
&nbsp;
        <span style="color: #808080; font-style: italic;"># Si le champ est editable dans la liste</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> db_field.<span style="color: black;">name</span> <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">self</span>.<span style="color: black;">list_editable</span> <span style="color: #ff7700;font-weight:bold;">and</span> <span style="color: #008000;">hasattr</span><span style="color: black;">&#40;</span>formfield<span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'choices'</span><span style="color: black;">&#41;</span>:
&nbsp;
            <span style="color: #808080; font-style: italic;"># On tente de récupérer la query en cache</span>
            cache_attr_name <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">'_%s_cache'</span> % db_field.<span style="color: black;">name</span>
            choices_cache <span style="color: #66cc66;">=</span> <span style="color: #008000;">getattr</span><span style="color: black;">&#40;</span>request<span style="color: #66cc66;">,</span> cache_attr_name<span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">if</span> choices_cache <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #008000;">None</span>:
                formfield.<span style="color: black;">choices</span> <span style="color: #66cc66;">=</span> choices_cache
&nbsp;
            <span style="color: #808080; font-style: italic;"># Pas de cache, on force Django à faire la query en accédant</span>
            <span style="color: #808080; font-style: italic;"># au descripteur .choices et on met le resultat</span>
            <span style="color: #808080; font-style: italic;"># en cache</span>
            <span style="color: #ff7700;font-weight:bold;">else</span>:
                <span style="color: #008000;">setattr</span><span style="color: black;">&#40;</span>request<span style="color: #66cc66;">,</span> cache_attr_name<span style="color: #66cc66;">,</span> formfield.<span style="color: black;">choices</span><span style="color: black;">&#41;</span>
&nbsp;
        <span style="color: #808080; font-style: italic;"># On retourne le champ de notre formulaire avec sa valeur mise</span>
        <span style="color: #808080; font-style: italic;"># en cache</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> formfield</pre></td></tr></table></div>

<p>Malheureusement, il peut arriver qu&#8217;il y ait tellement d&#8217;objets que c&#8217;est votre navigateur qui panique. En effet, si vous avez un modèle <code>Promotion</code> avec un lien vers un modèle <code>Produit</code> et que vous avez 5000 produits en base, vous allez créer 20 <code>&lt;select&gt;</code> avec 5000 <code>&lt;options&gt;</code> dedans. 100000 balises dans une page, ça peut faire mal.</p>
<p>Dans ce cas, il vaut mieux désactiver la possibilité de faire un drop down, et mettre un champ text à la place dans lequel on entre un ID en utilisant :</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> VotreClasseAdmin<span style="color: black;">&#40;</span>admin.<span style="color: black;">ModelAdmin</span><span style="color: black;">&#41;</span>
&nbsp;
     raw_id_fields <span style="color: #66cc66;">=</span> <span style="color: black;">&#40;</span><span style="color: #483d8b;">'nom_de_votre_champ'</span><span style="color: #66cc66;">,</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Django n&#8217;est pas chien, et vous mettra un petit bouton en forme de loupe pour chercher l&#8217;ID dont vous avez besoin.</p>
<p>Si vous avez beaucoup de ForeignKey <strong>non éditables</strong> (<code>readonly_fields</code>), vous pouvez aussi vous fendre d&#8217;un <code>select_related</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> VotreClasseAdmin<span style="color: black;">&#40;</span>admin.<span style="color: black;">ModelAdmin</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> queryset<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: #66cc66;">,</span> request<span style="color: black;">&#41;</span>:
        <span style="color: #808080; font-style: italic;"># On filtre le queryset que Django va utiliser pour populer la liste</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">super</span><span style="color: black;">&#40;</span>MyAdmin<span style="color: #66cc66;">,</span> <span style="color: #008000;">self</span><span style="color: black;">&#41;</span>.<span style="color: black;">queryset</span><span style="color: black;">&#40;</span>request<span style="color: black;">&#41;</span>.<span style="color: black;">select_related</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'myfield'</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Ça ne marche que sur les non éditables, car pour eux Django ne créé pas de champ de formulaire.</p>


feed_id: http://sametmax.com/?p=12248
title: Passer d’un clé Putty (ppk) à une clé OpenSSH
uri: Passer-d-un-clé-Putty-(ppk)-à-une-clé-OpenSSH
url: http://sametmax.com/passer-dun-cle-putty-ppk-a-une-cle-openssh/
content:
<p>Cas d&#8217;école, mon client me donne la clé pour accéder à son instance Amazon (bouh !) et il me file une clé Putty puisqu&#8217;il est sous Windows. </p>
<p>Heureusement, Putty existe aussi sous nunux. Par exemple sous Ubuntu :</p>
<pre>sudo apt-get install putty-tools</pre>
<p>Et il embarque tout ce qu&#8217;il faut pour convertir sa clé :</p>
<pre>
puttygen cle.ppk -O public-openssh -o nouvelle_cle.pub
puttygen cle.ppk -O private-openssh -o nouvelle_cle</pre>
<p>Y a plus qu&#8217;à mettre dans son dossier <code>.ssh</code>. En prime, je rajoute généralement ça dans <code>.ssh/config</code> :</p>
<pre>Host ip ou domaine
HostName ip ou domaine
User username pour le server
IdentityFile ~/.ssh/nouvelle_cle</pre>
<p>Comme ça pas besoin de sélectionner la clé manuellement à chaque connexion, si SSH voit cette IP, il me prend la bonne clé.</p>
<p>Mon dossier .ssh est un simple lien vers le vrai dossier dans la partition <a href="http://sametmax.com/eviter-davoir-la-queue-a-lair-en-publique-avec-truecrypt/">Truecrypt</a>. Malgré la disparition du projet, j&#8217;ai pas trouvé mieux.</p>


feed_id: http://sametmax.com/?p=12242
title: Multiboards a été migré
uri: Multiboards-a-été-migré
url: http://sametmax.com/multiboards-a-ete-migre/
content:
<p><a href="http://multiboards.net/">multiboards.net</a>, la page Web qu&#8217;on trempe dans son café, a été migrée. Comme il n&#8217;y a aucune donnée associée, ben, le truc n&#8217;a pas bougé, dont vous le retrouverez tel qu&#8217;avant.</p>
<p>Plusieurs personnes nous ont demandé le code source. La raison pour laquelle il n&#8217;est pas publié, c&#8217;est que c&#8217;est un amas de code vraiment peu ragoutant, et qu&#8217;il faudrait vraiment le nettoyer pour éviter que la honte ne s&#8217;abatte sur nous.</p>
<p>Max voudrait en faire un truc personnalisable, avec des widgets, et tout, à la netwibes mais en plus simple. Je pense que ça n&#8217;arrivera jamais :)</p>


feed_id: http://sametmax.com/?p=12269
title: Travailler sur une lib externe à votre projet proprement en Python
uri: Travailler-sur-une-lib-externe-à-votre-projet-proprement-en-Python
url: http://sametmax.com/travailler-sur-une-lib-externe-a-votre-projet-proprement-en-python/
content:
<p>Quand on a une lib externe en dépendance à son projet, on veut être capable de l&#8217;importer MAIS pouvoir en modifier le code.</p>
<p>L&#8217;installer avec <code>pip</code> ou python <code>setup.py install</code> va copier le code dans le dossier <code>site-packages</code> et ce n&#8217;est pas ce que l&#8217;on veut car ça oblige à refaire l&#8217;installation à chaque modif.</p>
<p>Le mettre dans un dossier &#8220;libs&#8221; qu&#8217;on ajoute au <code>PYTHON PATH</code> ou pire, ajouter chaque dépendance au <code>PYTHON PATH</code> n&#8217;est pas une solution qu&#8217;on est fier d&#8217;exhiber au hackerspace du coin.</p>
<p>On s&#8217;en remet donc généralement à un symlink, sans savoir qu&#8217;il existe en fait un outil fait pour ça :</p>

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

<p>Cette commande va ajouter des entrées spéciales dans des fichiers placés dans <code>site-packages</code> qui vont vous permettre d&#8217;utiliser votre lib comme si elle était installée. Mais en vérité il va chercher le code dans votre dossier de dev, donc si vous modifiez le code, vous avez toujours la version de votre lib la plus fraîche.</p>
<p>Une fois qu&#8217;on a une lib stable, on peut retirer ce lien avec :</p>

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

<p>Et installer la lib normalement.</p>
<p>Notez que tout ceci ne fonctionne que si le <code>setup.py</code> utilise <code>setuptools</code> et non <code>distutils</code> qui provoque l&#8217;erreur <em>error: invalid command &#8216;develop&#8217;</em>.</p>
<p>Comme <code>setuptools</code> inclut maintenant le meilleur de <code>distutils</code>, on peut remplacer :</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;">distutils</span>.<span style="color: black;">core</span> <span style="color: #ff7700;font-weight:bold;">import</span> setup</pre></td></tr></table></div>

<p>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;">from</span> setuptools <span style="color: #ff7700;font-weight:bold;">import</span> setup</pre></td></tr></table></div>

<p>Sans soucis.</p>
<p><code>pip</code> vient lui aussi avec un outil pour ça en la forme du flag <code>-e</code> qui fait exactement la même chose. Exemple :</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> <span style="color: #660033;">-e</span> <span style="color: #000000; font-weight: bold;">/</span>chemin<span style="color: #000000; font-weight: bold;">/</span>local<span style="color: #000000; font-weight: bold;">/</span>vers<span style="color: #000000; font-weight: bold;">/</span>projet</pre></td></tr></table></div>

<p>Cela fonctionne comme pour <code>python setup.py develop --uninstall</code> mais on bénéficie de tous les goodies de <code>pip</code> en prime.</p>
<p>Néanmoins, <code>pip</code> pousse plus loin l&#8217;automatisation. Si vous faites <code>pip install -e</code> sur un repo distant, il va également cloner pour vous le code.</p>
<p>Ex :</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> <span style="color: #660033;">-e</span> <span style="color: #c20cb9; font-weight: bold;">git</span>+https:<span style="color: #000000; font-weight: bold;">//</span><span style="color: #c20cb9; font-weight: bold;">git</span><span style="color: #000000; font-weight: bold;">@</span>github.com<span style="color: #000000; font-weight: bold;">/</span>sametmax<span style="color: #000000; font-weight: bold;">/</span>minibelt.git<span style="color: #666666; font-style: italic;">#egg=minibelt</span></pre></td></tr></table></div>

<p>Et on retrouvera un clone du projet dans <code>/chemin/vers/virtualenv/src/</code> qui sera importable, modifiable et pushable. Le résultat est automatisable, puisque <code>pip freeze</code> le prend en compte:</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="bash" style="font-family:monospace;">$ pip freeze
<span style="color: #007800;">argparse</span>==1.2.1
<span style="color: #660033;">-e</span> <span style="color: #c20cb9; font-weight: bold;">git</span>+https:<span style="color: #000000; font-weight: bold;">//</span><span style="color: #c20cb9; font-weight: bold;">git</span><span style="color: #000000; font-weight: bold;">@</span>github.com<span style="color: #000000; font-weight: bold;">/</span>sametmax<span style="color: #000000; font-weight: bold;">/</span>minibelt.git<span style="color: #000000; font-weight: bold;">@</span>b898155b40d7de73cc404db7d274128f2b2fc330<span style="color: #666666; font-style: italic;">#egg=minibelt-master</span>
<span style="color: #007800;">wsgiref</span>==0.1.2</pre></td></tr></table></div>

<p>L&#8217;URL est assez batarde à trouver par contre, car elle doit toujours finir par <code>#egg=nom-du-projet</code> et commencer par un double protocole, celui du VCS et celui du transport.</p>
<p>P.S: j&#8217;ai remis la coloration syntaxique et les iframes (donc la musique). J&#8217;aime bien ce thème là, mais la header chie sa mère. Est-ce que vous l&#8217;aimez suffisamment pour que je me casse le cul à le réparer ?</p>


feed_id: http://sametmax.com/?p=12376
title: Bien nommer ses variables en Python
uri: Bien-nommer-ses-variables-en-Python
url: http://sametmax.com/bien-nommer-ses-variables-en-python/
content:
<blockquote><p>There are only two hard things in Computer Science: cache invalidation and naming things.</p></blockquote>
<p><em>Phil Karlton</em></p>
<p>Utiliser des bons noms est le geste de documentation le plus important d&#8217;un code. Je ne parle pas de bien formater le nom des variables. Pour ça, il y a le PEP8 et ce qu&#8217;il recommande tient en 3 lignes :</p>
<ul>
<li>Le nom des classes en CamelCase</li>
<li>Les (pseudo) constantes en UPPER_CASE</li>
<li>Le reste en snake_case</li>
</ul>
<p>C&#8217;est tout.</p>
<p>Non, je parle de choisir un nom adapté et descriptif.</p>
<p>Le post est long, et vous savez que quand le post est long, je vous mets une musique d&#8217;attente.</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/4TV_128Fz2g?version=3&#038;rel=1&#038;fs=1&#038;showsearch=0&#038;showinfo=1&#038;iv_load_policy=1&#038;wmode=transparent' frameborder='0'></iframe></span></p>
<h2>Explicit is better than implicit</h2>
<p>En Python, il n&#8217;y a pas de déclaration de type. Le nom d&#8217;une variable a donc d&#8217;autant plus d&#8217;importance pour expliquer ce qu&#8217;il y a dedans.</p>
<p>Prenez cet exemple :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">best <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>
<span style="color: #ff7700;font-weight:bold;">for</span> k<span style="color: #66cc66;">,</span> v <span style="color: #ff7700;font-weight:bold;">in</span> data.<span style="color: black;">items</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">if</span> v <span style="color: #66cc66;">&gt;</span> top:
        best.<span style="color: black;">append</span><span style="color: black;">&#40;</span>k<span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Quand on lit ce bout de code, on se demande :</p>
<ul>
<li>Best ? Mais best en quoi ?</li>
<li>Que contient data ?</li>
<li>Quel est la nature de top ?</li>
</ul>
<p>Maintenant, avec des noms explicites :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">best_players <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>
<span style="color: #ff7700;font-weight:bold;">for</span> player<span style="color: #66cc66;">,</span> score <span style="color: #ff7700;font-weight:bold;">in</span> data.<span style="color: black;">items</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">if</span> score <span style="color: #66cc66;">&gt;</span> top_score :
        best_players.<span style="color: black;">append</span><span style="color: black;">&#40;</span>player<span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>On comprend tout de suite de quoi il est question. L&#8217;algo n&#8217;a pas changé, seul le nommage a changé.</p>
<p>Et si on passe à une écriture plus compacte, le gain est encore plus net :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">best <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: #66cc66;">,</span> v <span style="color: #ff7700;font-weight:bold;">in</span> data.<span style="color: black;">items</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">if</span> k <span style="color: #66cc66;">&gt;</span> top<span style="color: black;">&#93;</span></pre></td></tr></table></div>

<p>VS</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">best_players <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span>player <span style="color: #ff7700;font-weight:bold;">for</span> player<span style="color: #66cc66;">,</span> score <span style="color: #ff7700;font-weight:bold;">in</span> data.<span style="color: black;">items</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">if</span> score <span style="color: #66cc66;">&gt;</span> top_score<span style="color: black;">&#93;</span></pre></td></tr></table></div>

<p>Parfois, on veut la concision, mais faute de nommage, on doit se retourner vers les commentaires :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># Get players with the best scores</span>
best <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: #66cc66;">,</span> v <span style="color: #ff7700;font-weight:bold;">in</span> data.<span style="color: black;">items</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">if</span> k <span style="color: #66cc66;">&gt;</span> top<span style="color: black;">&#93;</span></pre></td></tr></table></div>

<p>Néanmoins, si on doit faire le choix entre commenter et bien nommer, le nommage doit avoir priorité. Le commentaire est important, mais c&#8217;est le dernier recours d&#8217;un code qui n&#8217;est pas explicite. Avoir un code clair doit être l&#8217;objectif premier. Ensuite, seulement, on le commente (abondamment toutefois, faut pas être radin).</p>
<p>Si vous avez suivi, je nomme mes variables en fonction de leur nature, pas leur type. On peut utiliser les règles de l&#8217;orthographe pour encore plus de précision, par exemple le pluriel.</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">fruits <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;kiwi&quot;</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">&quot;banane&quot;</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'poire'</span><span style="color: black;">&#93;</span>
<span style="color: #ff7700;font-weight:bold;">for</span> fruit <span style="color: #ff7700;font-weight:bold;">in</span> fruits:
    <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>fruit<span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>J&#8217;utilise le pluriel pour une liste de données, qui va donc potentiellement contenir plusieurs fruits. Mais j&#8217;utilise un singulier dans la boucle pour le fruit en court.</p>
<p>L&#8217;utilisation d&#8217;adjectifs est aussi le bienvenu :</p>
<p><code>fruits</code> peut devenir, après un traitement <code>filtered_fruits</code>, indiquant que la liste a subit un filtrage. Les mots en &#8220;ed&#8221; en anglais aident beaucoup à la qualification.</p>
<p>On évite au maximum les variables courtes. Certains cas sont néanmoins tolérés. Le premier est l&#8217;utilisation de <code>i</code>, <code>x</code>, <code>y</code>et <code>z</code> pour des indices.</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> i<span style="color: #66cc66;">,</span> fruit <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">enumerate</span><span style="color: black;">&#40;</span>fruits<span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;"># faire un truc</span></pre></td></tr></table></div>

<p>Les indices sont quelque chose de tellement courant en informatique qu&#8217;on ne va pas se gaver à l&#8217;appeler &#8220;indice&#8221; à chaque fois.</p>
<p>Le second est dans le cadre scientifique. On a souvent des variables pour un algo, des coordonnées, des valeurs géométriques ou mathématiques, qui n&#8217;ont pas de dénomination. Dans ce cas, inutile d&#8217;essayer d&#8217;inventer une nomenclature tordue. Exemple typique, <a href="http://equi4.com/md5/pymd5.py">l&#8217;algo pour pondre un MD5</a>. Mais il faut compenser par des commentaires, sinon on s&#8217;y perd.</p>
<p>Il ne faut pas avoir peur des noms longs. Si, j&#8217;ai un jeu de données, que je filtre plusieurs fois, il est de bon ton de distinguer les différents jeux avec des noms détaillés :</p>

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

<p>Faire des noms de plus de 10 caractères n&#8217;est pas sale. On est pas sur un tableau des scores d&#8217;une borne d&#8217;arcade des années 80.</p>
<p>J&#8217;utilise bien entendu des noms en anglais, ce qui est toujours préférable, mais si vous devez en mettre en fr, évitez à tout prix les accents malgré la possibilité de les utiliser en Python 3.</p>
<h2>Conventions</h2>
<p>Il existe quelques noms qui sont toujours utilisés de la même façon en Python.</p>
<p><code>self</code> et <code>cls</code> sont les plus connus, en j&#8217;en parle déjà dans <a href="https://duckduckgo.com/l/?kh=-1&#038;uddg=http%3A%2F%2Fsametmax.com%2Fle-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">le dossier sur la POO</a>.</p>
<p>Il y a <code>args</code> et <code>kwargs</code>, qu&#8217;on utilise avec l&#8217;opérateur splat, dont je parle <a href="https://duckduckgo.com/l/?kh=-1&#038;uddg=http%3A%2F%2Fsametmax.com%2Foperateur-splat-ou-etoile-en-python%2F">ici</a>.</p>
<p>Et puis il y en a de plus discrets.</p>
<p><code>_</code> est utilisé pour une variable qu&#8217;on ignore. Certaines opérations, comme l&#8217;unpacking, supposent la création de plusieurs variables. Si on n&#8217;est pas intéressé par l&#8217;une d&#8217;elles, on peut le signaler. Par exemple, l&#8217;ORM django permet d&#8217;obtenir un objet, et si il n&#8217;existe pas, de le créer. Cette fonction retourne un tuble (objet, bool), l&#8217;élément indiquant si l&#8217;objet a été créé ou non. Si cette information nous intéresse :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #dc143c;">user</span><span style="color: #66cc66;">,</span> created <span style="color: #66cc66;">=</span> User.<span style="color: black;">objects</span>.<span style="color: black;">get_or_create</span><span style="color: black;">&#40;</span>username<span style="color: #66cc66;">=</span><span style="color: #483d8b;">&quot;sam&quot;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Si cette information ne nous intéresse pas :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #dc143c;">user</span><span style="color: #66cc66;">,</span> _ <span style="color: #66cc66;">=</span> User.<span style="color: black;">objects</span>.<span style="color: black;">get_or_create</span><span style="color: black;">&#40;</span>username<span style="color: #66cc66;">=</span><span style="color: #483d8b;">&quot;sam&quot;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Ainsi le lecteur saura qu&#8217;il peut ignorer cette variable quand il parcourt le code.</p>
<p>Il y a aussi les alias. On ne peut pas utiliser certains noms comme <code>list</code> ou <code>id</code> qui sont des fonctions existantes en Python.</p>
<p>On s&#8217;arrange généralement en trouvant un synonyme, mais si ce n&#8217;est pas pratique, on change une lettre. <code>list</code> devient <code>lst</code> (rappelez vous que <code>list</code> est un nom déjà assez pourri, nommez plutôt le contenu), <code>class</code> devient <code>klass</code>, <code>dict</code> devient <code>dct</code>, etc.</p>
<p>Si on ne peut pas le faire, la convention est de rajouter un underscore à la fin du nom : <code>id</code> devient <code>id_</code>, <code>max</code> devient <code>max_</code>&#8230; Mais faites l&#8217;effort, avant, de chercher un synonyme. Je vois trop souvent des <code>from_</code>/<code>to</code> alors que certains contextes permettent parfaitement de les nommer <code>start</code>/<code>end</code> ou <code>source</code>/<code>destination</code>.</p>
<p>A ne pas confondre avec l&#8217;underscore AVANT le nom, qui est une convention pour dire qu&#8217;une variable ne fait pas partie de l&#8217;API publique.</p>
<p>Ce sont des béquilles, le choix d&#8217;un nom judicieux et clair est toujours préférable, mais ce sont des béquilles utiles.</p>
<h2>Savoir quand nommer</h2>
<p>Au delà de donner un bon nom, il y a le fait de choisir quand il faut nommer, et quand il faut éviter de le faire.</p>
<p>Si seul le résultat final d&#8217;un traitement m&#8217;intéresse, alors, il vaut mieux utiliser une seule variable et mettre le nouveau résultat dedans à chaque fois :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">fstab <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span>line.<span style="color: black;">strip</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">for</span> line <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">open</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'/etc/fstab'</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">if</span> line<span style="color: black;">&#93;</span>
fstab <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span>line.<span style="color: black;">lower</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">for</span> line <span style="color: #ff7700;font-weight:bold;">in</span> fstab <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> line.<span style="color: black;">startswith</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'#'</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span>
fstab <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span>line.<span style="color: black;">split</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#91;</span>:<span style="color: #ff4500;">3</span><span style="color: black;">&#93;</span> <span style="color: #ff7700;font-weight:bold;">for</span> line <span style="color: #ff7700;font-weight:bold;">in</span> fstab<span style="color: black;">&#93;</span></pre></td></tr></table></div>

<p>il faut aussi savoir quand ne pas du tout créer une variable :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">row <span style="color: #66cc66;">=</span> line.<span style="color: black;">strip</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>.<span style="color: black;">split</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">for</span> col <span style="color: #ff7700;font-weight:bold;">in</span> row:
    <span style="color: #808080; font-style: italic;"># do something</span></pre></td></tr></table></div>

<p>ici, la variable intermédiaire est inutile :</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> col <span style="color: #ff7700;font-weight:bold;">in</span> line.<span style="color: black;">strip</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>.<span style="color: black;">split</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;"># do something</span></pre></td></tr></table></div>

<p>L&#8217;inverse est aussi vrai :</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> col <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: black;">&#91;</span><span style="color: #008000;">int</span><span style="color: black;">&#40;</span>x<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> line.<span style="color: black;">strip</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>.<span style="color: black;">split</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span>:
    <span style="color: #808080; font-style: italic;"># do something</span></pre></td></tr></table></div>

<p>La ligne devient beaucoup trop complexe, et ajouter une variable intermédiaire avec un bon nom va améliorer la lisibilité du programme :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">numeric_col <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span><span style="color: #008000;">int</span><span style="color: black;">&#40;</span>x<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> line.<span style="color: black;">strip</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>.<span style="color: black;">split</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span>
<span style="color: #ff7700;font-weight:bold;">for</span> col <span style="color: #ff7700;font-weight:bold;">in</span> numeric_col:
    <span style="color: #808080; font-style: italic;"># do something</span></pre></td></tr></table></div>

<p>On pourrait croire que je précise le type ici en utilisant &#8220;numeric&#8221;, mais je n&#8217;ai pas utilisé integer ou float. J&#8217;ai précisé la nature : des colonnes numériques. Il se trouve que pour des données aussi brutes, la nature se rapproche du type.</p>
<p>Si vous êtes du genre à utiliser des <a href="https://duckduckgo.com/l/?kh=-1&#038;uddg=http%3A%2F%2Fsametmax.com%2Ffonctions-anonymes-en-python-ou-lambda%2F">lambdas</a>, cela s&#8217;applique aussi à vous.</p>
<p>Pour quelque chose de simple, une lambda inline est très lisible :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #008000;">sorted</span><span style="color: black;">&#40;</span>scores.<span style="color: black;">items</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span> key<span style="color: #66cc66;">=</span><span style="color: #ff7700;font-weight:bold;">lambda</span> score: score<span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Mais pour quelque chose de complexe, une fonction complète est bien plus adapté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;">def</span> calculate_rank<span style="color: black;">&#40;</span>score<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">sum</span><span style="color: black;">&#40;</span>goals <span style="color: #ff7700;font-weight:bold;">for</span> sort<span style="color: #66cc66;">,</span> goal <span style="color: #ff7700;font-weight:bold;">in</span> score<span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span> <span style="color: #ff7700;font-weight:bold;">if</span> sort <span style="color: #66cc66;">==</span> <span style="color: #483d8b;">'A'</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #008000;">sorted</span><span style="color: black;">&#40;</span>scores.<span style="color: black;">items</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span> key<span style="color: #66cc66;">=</span>calculate_rank<span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Plutôt qu&#8217;un horrible :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #008000;">sorted</span><span style="color: black;">&#40;</span>scores.<span style="color: black;">items</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span> key<span style="color: #66cc66;">=</span><span style="color: #ff7700;font-weight:bold;">lambda</span> x: <span style="color: #008000;">sum</span><span style="color: black;">&#40;</span>g <span style="color: #ff7700;font-weight:bold;">for</span> s<span style="color: #66cc66;">,</span> g <span style="color: #ff7700;font-weight:bold;">in</span> x<span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span> <span style="color: #ff7700;font-weight:bold;">if</span> s <span style="color: #66cc66;">==</span> <span style="color: #483d8b;">'A'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Pourquoi je parle de lambda alors qu&#8217;on est sur du nommage ? Parce qu&#8217;une lambda est anonyme, alors qu&#8217;une fonction normale a un nom. Et ce nom exprime l&#8217;action de la fonction. Il documente.</p>
<h2>Habitudes stylistiques</h2>
<p>Ces règles là ne sont pas officielles, mais j&#8217;ai pu les constater dans nombre de bons codes.</p>
<p>La nom d&#8217;une fonction/méthode est aussi important, sinon plus, que le nom d&#8217;une variable. Il n&#8217;est pas rare que j&#8217;écrive des fonctions avec des noms bien dodus comme :</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> get_last_downloaded_shemale_vids<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Si on oublie la docstring, on a déjà une bonne idée de ce que cette fonction fait. Cela n&#8217;empêche pas de docstringuer quand même pour annoncer des subtilités sur les types, les potentiels side effects, des choses à savoir sur le temps d&#8217;exécution, le format, les perfs, etc.</p>
<p>Mais il arrive souvent qu&#8217;une fonction ne fasse pas quelque chose d&#8217;aussi concret. Prenez par exemple une fonction dont le but est de sluggifier les strings d&#8217;une list.</p>
<p>Si la fonction transforme la liste, on va utiliser un verbe dans le nom :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">slugify_items<span style="color: black;">&#40;</span>data<span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Si par contre la fonction retourne une liste avec les éléments modifiés, on va utiliser le participe passé :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">data <span style="color: #66cc66;">=</span> slugified_items<span style="color: black;">&#40;</span>data<span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>C&#8217;est subtil, mais la sémantique est différente. Dans le premier cas, on s&#8217;attend à un effet de bord. Dans le second cas, on s&#8217;attend à une nouvelle liste, ou comme souvent en Python, à un <a href="http://sametmax.com/comment-utiliser-yield-et-les-generateurs-en-python/">générateur</a>.</p>
<p>Quand on a affaire à une méthode en Python, on utilise rarement le préfixe <code>get_</code>. Personnellement je l&#8217;utilise parfois pour des actions complexes, ou des méthodes de classe.</p>
<p>Mais généralement, on préférera utiliser directement le nom de ce qu&#8217;on veut récupérer. Exemple :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">comments <span style="color: #66cc66;">=</span> blog_post.<span style="color: black;">get_comments</span><span style="color: black;">&#40;</span>spam<span style="color: #66cc66;">=</span><span style="color: #008000;">False</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># NON</span>
comments <span style="color: #66cc66;">=</span> blog_post.<span style="color: black;">comments</span><span style="color: black;">&#40;</span>spam<span style="color: #66cc66;">=</span><span style="color: #008000;">False</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># Oui</span></pre></td></tr></table></div>

<p>Si on n&#8217;a pas besoin de passer de paramètre, alors une <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-2/">property</a> est plus appropriée :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;">comments <span style="color: #66cc66;">=</span> blog_post.<span style="color: black;">comments</span> <span style="color: #808080; font-style: italic;"># Ouiiiiiiiiiiiiiii</span></pre></td></tr></table></div>

<p>J&#8217;en profite pour faire remarquer qu&#8217;il est très classe de prononcer plusieurs fois très vite &#8220;sans paramètre, une propriété est plus appropriée&#8221;.</p>
<p>Enfin, il arrive qu&#8217;on ait besoin de spécifier des rôles techniques et des interactions entre plusieurs bouts de code : hiérarchie, composition, dépendances, etc. Ce sont les choses les plus compliquées à comprendre quand on lit du code : voir le tableau au complet, ce qui lie les différents blocs.</p>
<p>Il ne faut pas hésiter à nommer ses éléments pour cela. Apprendre le nom des design patterns aide beaucoup, mais même si on n&#8217;est pas top moumoute niveau vocabulaire, on peut faire des choses aussi simple que :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">class</span> BaseAuthenticator<span style="color: black;">&#40;</span><span style="color: #008000;">object</span><span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;">#...</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> PwdAuthenticator<span style="color: black;">&#40;</span>BaseAuthenticator<span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;">#...</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> KeyAuthenticator<span style="color: black;">&#40;</span>BaseAuthenticator<span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;">#...</span></pre></td></tr></table></div>

<p>Si vous lisez <code>BaseAuthentificator</code>, vous n&#8217;avez pas besoin de voir qu&#8217;elle est parente d&#8217;autres classes plus bas pour savoir que ce n&#8217;est probablement pas une classe instanciable, mais sans doute une classe interface ou une classe abstraite. De quoi se faciliter une lecture en diagonale.</p>
<h2>FAIL</h2>
<p>Voici quelques exemples de noms qui ratent complètement l&#8217;objectif de documentation :</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;">def</span> do_query_database<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;"># ...</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> query_database<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;"># ...</span>
    do_query_database<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    <span style="color: #808080; font-style: italic;"># ...</span></pre></td></tr></table></div>

<p>J&#8217;en croise dans le code source de Django, et ça me fait hurler. Sérieux ça veut dire quoi ? Qu&#8217;est-ce qui a été extrait ? Dans quel but ? On a plus de question APRÈS avoir lu le nom qu&#8217;avant, c&#8217;est encore pire qu&#8217;un mauvais nom, c&#8217;est un nom méchant.</p>
<p>Dans ce cas, il faut essayer d&#8217;expliquer au maximum ce que l&#8217;appendice &#8211; qui va me faire choper une péritonite &#8211; que vous avez mis de côté fait :</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;">def</span> excute_and_send_query<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;"># ...</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> query_database<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;"># ...</span>
    excute_and_send_query<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    <span style="color: #808080; font-style: italic;"># ...</span></pre></td></tr></table></div>

<p>Un truc également exaspérant, c&#8217;est l&#8217;usage d&#8217;un vocabulaire ambigu :</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> make_best_player_list<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;"># ...</span></pre></td></tr></table></div>

<p>On sait ce que ça fait, ça fabrique une liste des meilleurs joueurs. Le contexte nous permet d&#8217;évaluer le résultat le plus probable. Maintenant un cas beaucoup moins clair :</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> make_query<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;"># ...</span></pre></td></tr></table></div>

<p>Ca envoie la requête, ça construit la requête ou les deux ? <code>Make</code> est un mot qui peut vouloir dire fabriquer ou exécuter. Ici il vaut mieux utiliser un vocabulaire plus explicite comme :</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> build_sql_query<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;"># ...</span></pre></td></tr></table></div>

<p>ou</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> send_db_query<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;"># ...</span></pre></td></tr></table></div>

<p>Là on sait qui fait quoi. Quitte à faire :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> db_query<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    build_sql_query<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    send_db_query<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Et oui, diviser le travail en plusieurs sous unités bien nommées, puis les regrouper dans un bloc plus général est aussi une forme de documentation. Créer des fonctions n&#8217;est pas qu&#8217;une question de maintenance ou de perf. </p>
<p>Savoir bien nommer les choses vient avec de l’entraînement. Au début, il faut prendre le temps de le faire. Il faut s&#8217;arrêter, et se mettre à la place d&#8217;un autre dev qui n&#8217;a pas encore eu son café. </p>
<p>Allez, détendez-vous, ce blog est plein de code qui ne suit pas les conseils de cet article. Faites juste au mieux ok ?</p>


feed_id: http://sametmax.com/?p=12332
title: Restauration des fonctionnalités
uri: Restauration-des-fonctionnalités
url: http://sametmax.com/restauration-des-fonctionnalites/
content:
<p>Après les iframes et la coloration syntaxique, le <a href="http://sametmax.com/contactez-nous/">formulaire de contact</ahref=>, le <a href="http://bridge.suumitsu.eu/?action=display&#038;bridge=TwitterBridge&#038;u=sam_et_max&#038;format=AtomFormat">flux rss des tweets</a> et le <a href="http://sametmax.com/planet-python-fr/">planet Python fr</a> sont de nouveau opérationnels. </p>
<p>Ça me fait penser que si vous connaissez des blogs fr sur Python, proposez les pour le planet.</p>


feed_id: http://sametmax.com/?p=12353
title: Le compteur mal connu : l’HyperLogLog
uri: Le-compteur-mal-connu-l-HyperLogLog
url: http://sametmax.com/le-compteur-mal-connu-lhyperloglog/
content:
<p>Non, <a href="https://en.wikipedia.org/wiki/HyperLogLog">ce n&#8217;est pas une faute de frappe</a>. l&#8217;HyperLogLog est un algo qui permet de compter approximativement des éléments uniques en prenant très peu de mémoire.</p>
<p>Prenez par exemple un compteur d&#8217;IP uniques. En Python, on l&#8217;implémenterait en mettant les adresses IP dans un <code>set()</code> (puisqu&#8217;ils éliminent les doublons) et pour obtenir le nombre d&#8217;IP uniques, on ferait <code>len()</code> sur le <code>set</code>.</p>
<p>Une bonne stratégie, performante (les sets sont très rapides pour ce genre d&#8217;usage), simple, mais avec un défaut : la taille du <code>set</code> ne va cesser d&#8217;augmenter au fur et à mesure qu&#8217;on le remplit d&#8217;IP puisqu&#8217;il nous faut l&#8217;historique de toutes celles rencontrées pour éviter les doublons.</p>
<p>L&#8217;HyperLogLog répond à cette problématique : il tient un journal probabiliste qui va se remplir au fur et à mesure qu&#8217;on rencontre des nouveaus éléments. On peut ensuite demander au journal combien d&#8217;éléments uniques il a rencontré, et il répond avec une marge d&#8217;erreur.</p>
<p><strong>Avantage </strong>: la taille en mémoire est fixe.<br />
<strong>Désavantage </strong>: le compteur n&#8217;est pas parfaitement précis.</p>
<p>La précision obtenue est dépendante de la place en mémoire, par exemple si on on tolère 1% d&#8217;erreur, le journal prendra au maximum 12kb, permettant de compter jusqu&#8217;à 2^64 items.</p>
<p>Bref, si vous faites juste un compteur à afficher en pied de page de votre site, c&#8217;est un très bon compromis. On peut accepter d&#8217;avoir un peu plus ou un peu moins de visiteurs que la réalité qui s&#8217;affiche, sachant que la stat elle-même n&#8217;est pas vraiment réprésentative de la réalité (IP != de visiteurs uniques).</p>
<p>En Python, il existe une lib (uniquement 2.7 il me semble) pour ça :</p>
<pre lang="bash>pip install hyperloglog</pre>
<p>Et ça s&#8217;utilise très simplement :</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> hyperloglog<span style="color: #66cc66;">,</span> <span style="color: #dc143c;">random</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> hll <span style="color: #66cc66;">=</span> hyperloglog.<span style="color: black;">HyperLogLog</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0.01</span><span style="color: black;">&#41;</span>  <span style="color: #808080; font-style: italic;"># on accepte une erreur de 1%</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> hll.<span style="color: black;">add</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;119.250.66.95&quot;</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>hll<span style="color: black;">&#41;</span>  
<span style="color: #ff4500;">1</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> hll.<span style="color: black;">add</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;119.250.66.95&quot;</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>hll<span style="color: black;">&#41;</span>  
<span style="color: #ff4500;">1</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> hll.<span style="color: black;">add</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;219.81.118.147&quot;</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>hll<span style="color: black;">&#41;</span>  
<span style="color: #ff4500;">2</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">for</span> x <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;">1000</span><span style="color: black;">&#41;</span>:
... <span style="color: black;">ip</span> <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;.&quot;</span>.<span style="color: black;">join</span><span style="color: black;">&#40;</span><span style="color: #008000;">str</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">random</span>.<span style="color: black;">randint</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">255</span><span style="color: black;">&#41;</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> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">4</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
... <span style="color: #ff7700;font-weight:bold;">print</span> ip
... <span style="color: black;">hll</span>.<span style="color: black;">add</span><span style="color: black;">&#40;</span>ip<span style="color: black;">&#41;</span>
114.208.49.91
11.72.239.16
67.56.229.66
191.62.59.163
61.104.232.43
110.58.69.141
246.123.30.234
244.246.65.219
98.93.193.114
185.143.143.69
191.177.161.213
...
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>hll<span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># 1000 items unique. Environ :)</span>
<span style="color: #ff4500;">1004</span></pre></td></tr></table></div>

<p>Vous pouvez également profiter de l&#8217;HyperLogLog via une <a href="http://tapoueh.org/blog/2013/02/25-postgresql-hyperloglog">extension PostGres</a> ou en utilisant une version récente de <a href="http://redis.io/commands#hyperloglog">Redis</a>.</p>
<p>La plupart des compteurs sur les sites sont complètement bidons, alors vous, honnête que vous êtes, embrassez l&#8217;approximatif ! C&#8217;est presque la vérité. Presque.</p>


feed_id: http://sametmax.com/?p=12393
title: L’équation du nichon
uri: L-équation-du-nichon
url: http://sametmax.com/lequation-du-nichon/
content:
<p>Alors que je remontais l&#8217;Ecosse en stop avec un vieil ami, nous nous sommes faits ramasser par des Suisses. On a terminé dans un village au dessus d&#8217;Inverness. Un de nos hôtes, bien pinté, nous confie de but en blanc avec son accent de Genève qu&#8217;il aime quand les femmes lui roulent la bite.</p>
<p>Je sais, ce n&#8217;est pas facile à expliquer sans geste. Vous voyez les brulures indiennes ? C&#8217;est le même principe, mais à la verticale, et sur sa teub.</p>
<p>Enrichi de cette révélation, j&#8217;ai compris à quelle point la diversité des plaisirs était vaste. Ici, parlant de la queue d&#8217;un inconnu suisse dans le décor de flashback de Highlanders, et surtout de la prise en main qu&#8217;il préférait, et qui me paraissant, à moi, parfaitement désagréable.</p>
<p>Malgré cela, je continue d&#8217;être surpris par la variété de manières de toucher des nibars.</p>
<p>Ma maman (avec laquelle je parle beaucoup de cul, allez comprendre mon évolution psychique plus tard) m&#8217;avait toujours dis qu&#8217;il fallait y aller tout doucement.</p>
<p>Mais sur le terrain, le manuel de formation ne sert plus à rien. Il y a celles qui aiment qu&#8217;on les caresse. Celles qui aiment qu&#8217;on les suce. Celles qui aiment qui les mordille. Les morde. Les prenne en main. Les malaxe. Les tire. Les tord. Les pince. Les giffle. Ou qu&#8217;on leur souffle doucement dessus. </p>
<p>Une meuf m&#8217;a sorti une fois qu&#8217;elle demandait à un copain boulanger de lui bouler les seins, comme les miches de pain, et qu&#8217;elle adorait ça.</p>
<p>Il y a les sensibles, et celles qui ne voient pas l&#8217;interêt. Les fragiles, et les masos. Les amoureuses de têton, et les fans de la colerette.</p>
<p>Et toutes s&#8217;attendent à ce qu&#8217;on sache quoi faire parce que &#8220;c&#8217;est pas bien compliqué&#8221;.</p>
<p>Bref, ayant hier couché avec une meuf qui adore qu&#8217;on lui tire-bouchonne les tétés, la mémoire de la précédente qui avait mal dès qu&#8217;on posait la main dessus m&#8217;est revenu en mémoire.</p>
<p>L&#8217;équation du nichon a trop d&#8217;inconnues pour être résolue a priori. Il faut de la data pour pouvoir en faire quelque chose. De la collecte IRL, avec une mise à jour régulière.</p>
<p>Aussi, en ce jour, je poste cet article solidaire de tous les hommes qui, une fois qu&#8217;ils ont retiré le soutif, doivent se lancer dans une étude empirique pour savoir quoi faire avec ces nouvelles mamelles.</p>
<p>Petite astuce cependant, apprenez à retirer un  soutien-gorge d&#8217;une main, quitte à vous entrainer seul. Ca coûte rien, et c&#8217;est la classe.</p>


feed_id: http://sametmax.com/?p=12279
title: Redis : pourquoi et comment ?
uri: Redis-pourquoi-et-comment
url: http://sametmax.com/redis-pourquoi-et-comment/
content:
<p>Redis fait partie de ces technologies tellement utiles et simples à mettre en oeuvre qu&#8217;il est facile d&#8217;oublier toutes les personnes qui ne savent toujours pas ce que c&#8217;est. D&#8217;autant plus qu&#8217;on l&#8217;associe avec beaucoup d&#8217;étiquettes : cache, queues, pub/sub, base de données, nosql&#8230; Et qu&#8217;est-ce que Redis comparé à Memcache, MongoDB, MySQL, RabbitMQ, des technos qui n&#8217;ont rien à voir et auxquelles on le compare ?</p>
<p>Bref, c&#8217;est pas clair tout ça.</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/6VAkOhXIsI0?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>Hello redis</h2>
<h3>D&#8217;abord, installer le bouzin. </h3>
<p>Si vous êtes sous Linux, Redis est dans votre gestionnaire de paquets. Par exemple, sous Ubuntu :</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> redis-server</pre></td></tr></table></div>

<p>Pour Mac, via macport :</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> port <span style="color: #c20cb9; font-weight: bold;">install</span> redis
<span style="color: #c20cb9; font-weight: bold;">sudo</span> port load redis</pre></td></tr></table></div>

<p>Je crois que <code>brew install redis</code> marche aussi pour les amateurs de homebrew.</p>
<p>Pour Windows, il y a un exe à télécharger <a href="https://github.com/MSOpenTech/redis/blob/2.8/bin/release/redis-2.8.17.zip">ici</a>.</p>
<p>Mais le plus fun avec redis, c&#8217;est que même quand il y a pas de binaire, c&#8217;est le truc le plus facile du monde <a href="https://github.com/MSOpenTech/redis/blob/2.8/bin/release/redis-2.8.17.zip">à compiler.</a> Et Dieu sait que je hais la compilation, donc quand je vous dis que c&#8217;est simple, c&#8217;est que c&#8217;est mega, ultra, simple.</p>
<h3>Ensuite lui faire dire bonjour.</h3>
<p>Utiliser Redis se fait à base de commandes, dont <a href="http://redis.io/commands">la liste est sur le site officiel</a>. On peut envoyer ces commandes depuis n&#8217;importe quel langage, mais Redis fournit un shell qui permet de rentrer ces commandes directement:</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="bash" style="font-family:monospace;">$ redis-cli <span style="color: #666666; font-style: italic;"># lancer le shell redis</span>
127.0.0.1:<span style="color: #000000;">6379</span><span style="color: #000000; font-weight: bold;">&gt;</span>  ECHO <span style="color: #ff0000;">&quot;Hello&quot;</span>
<span style="color: #ff0000;">&quot;Hello&quot;</span></pre></td></tr></table></div>

<h2>Redis comme base de données clés/valeurs expirables</h2>
<p>L&#8217;usage de base de Redis, c&#8217;est de stocker des valeurs associées à des clés. Le serveur Redis est comme un gigantesque Hash Map, dictionnaire Python, object Javascript, Array associatif en PHP&#8230; En premier lieu, donc, on utilise Redis pour stocker des choses ainsi :</p>
<pre>"cle1" => valeur1
"cle2" => valeur2
etc</pre>
<p>La clé doit être une chaîne de caractères, de préférence ASCII. La valeur peut être n&#8217;importe quoi, vraiment, mais généralement c&#8217;est un gros bloc de texte, un entier ou un blob binaire.</p>
<p>Ca s&#8217;utilise avec les commandes <code>SET</code> et <code>GET</code>, qui peuvent, comme toutes les commandes, être tapées dans le shell de Redis :</p>
<pre>127.0.0.1:6379> GET une_cle
(nil)
127.0.0.1:6379> SET une_cle "Une valeur"
OK
127.0.0.1:6379> GET une_cle
"Une valeur"
127.0.0.1:6379> SET une_cle 780708
OK
127.0.0.1:6379> GET une_cle
"780708"</pre>
<p>Ce genre d&#8217;usage est surtout sollicité pour stocker des paramètres de configurations ou des compteurs.</p>
<p>En effet, la plupart des opérations sur les clés sont atomiques, rendant ce genre d&#8217;usage idéal. On peut même incrémenter ou décrémenter une valeur avec <code>INCR</code> et <code>DECR</code> atomiquement :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="bash" style="font-family:monospace;">127.0.0.1:<span style="color: #000000;">6379</span><span style="color: #000000; font-weight: bold;">&gt;</span> INCR une_cle
<span style="color: #7a0874; font-weight: bold;">&#40;</span>integer<span style="color: #7a0874; font-weight: bold;">&#41;</span> <span style="color: #000000;">780709</span>
127.0.0.1:<span style="color: #000000;">6379</span><span style="color: #000000; font-weight: bold;">&gt;</span> INCR une_cle
<span style="color: #7a0874; font-weight: bold;">&#40;</span>integer<span style="color: #7a0874; font-weight: bold;">&#41;</span> <span style="color: #000000;">780710</span>
127.0.0.1:<span style="color: #000000;">6379</span><span style="color: #000000; font-weight: bold;">&gt;</span> DECR une_cle
<span style="color: #7a0874; font-weight: bold;">&#40;</span>integer<span style="color: #7a0874; font-weight: bold;">&#41;</span> <span style="color: #000000;">780709</span>
127.0.0.1:<span style="color: #000000;">6379</span><span style="color: #000000; font-weight: bold;">&gt;</span></pre></td></tr></table></div>

<p>Vous allez me dire, mais quel intérêt ? Je peux déjà faire ça avec une variable. Certes, mais Redis est accessible depuis n&#8217;importe quel programme de votre serveur. Vous pouvez donc facilement partager des valeurs entre vos processus. Par exemple, avec Django, on a souvent plusieurs workers WSGI, et Redis permet donc de partager des informations entre ces workers. Pour cette raison, on peut utiliser Redis pour créer un <a href="https://github.com/antirez/redlock-rb">lock partagé</a>.</p>
<p>Ainsi, un paramètre dynamique peut être changé et lu depuis tous les process de votre projet en utilisant Redis, et la valeur sera garantie d&#8217;être à jour. On peut bien entendu faire ça avec une base de données ordinaire, mais Redis a un plus : la performance.</p>
<p>En effet, Redis est par défaut configuré pour garder toutes les données de sa base en mémoire vive. Pour cette raison, il est très, très rapide, supportant 100000 lectures/écritures par seconde. Si vous comptez le nombre de visiteurs en ligne pour l&#8217;afficher sur chaque page, votre base de données vous dira merci de plutôt demander à Redis.</p>
<p>Plus encore, les clés peuvent expirer :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="bash" style="font-family:monospace;">127.0.0.1:<span style="color: #000000;">6379</span><span style="color: #000000; font-weight: bold;">&gt;</span> SET une_autre_cle <span style="color: #ff0000;">&quot;Tu ne le sais pas mais tu es deja mort&quot;</span>
OK
127.0.0.1:<span style="color: #000000;">6379</span><span style="color: #000000; font-weight: bold;">&gt;</span> EXPIRE une_autre_cle <span style="color: #000000;">5</span> <span style="color: #666666; font-style: italic;"># cette clé expire dans 5 secondes</span>
<span style="color: #7a0874; font-weight: bold;">&#40;</span>integer<span style="color: #7a0874; font-weight: bold;">&#41;</span> <span style="color: #000000;">1</span>
127.0.0.1:<span style="color: #000000;">6379</span><span style="color: #000000; font-weight: bold;">&gt;</span> GET une_autre_cle
<span style="color: #ff0000;">&quot;Tu ne le sais pas mais tu es deja mort&quot;</span>
127.0.0.1:<span style="color: #000000;">6379</span><span style="color: #000000; font-weight: bold;">&gt;</span> GET une_autre_cle
<span style="color: #ff0000;">&quot;Tu ne le sais pas mais tu es deja mort&quot;</span>
127.0.0.1:<span style="color: #000000;">6379</span><span style="color: #000000; font-weight: bold;">&gt;</span> GET une_autre_cle
<span style="color: #ff0000;">&quot;Tu ne le sais pas mais tu es deja mort&quot;</span>
127.0.0.1:<span style="color: #000000;">6379</span><span style="color: #000000; font-weight: bold;">&gt;</span> GET une_autre_cle
<span style="color: #7a0874; font-weight: bold;">&#40;</span>nil<span style="color: #7a0874; font-weight: bold;">&#41;</span>
127.0.0.1:<span style="color: #000000;">6379</span><span style="color: #000000; font-weight: bold;">&gt;</span> GET une_autre_cle
<span style="color: #7a0874; font-weight: bold;">&#40;</span>nil<span style="color: #7a0874; font-weight: bold;">&#41;</span></pre></td></tr></table></div>

<p>La limite en taille de ce qu&#8217;on peut stocker par couple est <a href="http://sametmax.com/les-limites-théoriques-de-redis/">assez large</a>.</p>
<p>On peut également utiliser <code>EXPIREAT</code> et un timestamp unique si on a une date en tête.</p>
<p>Cette caractéristique le rend similaire à Memcache, qui est basé sur des clés/valeurs en mémoire qui peuvent expirer. Et comme Memcache, cela fait de Redis un outil idéal pour gérer du cache : faites une opération longue, stockez-là avec une clé, mettez lui une date d&#8217;expiration et pouf, vous avez une valeur cachée globale à votre app.</p>
<p>Redis a néanmoins 3 différences majeures qui le sépare de Memcache :</p>
<ul>
<li>Redis sauvegarde régulièrement toutes les données sur le disque. Si vous rebootez le serveur, vous perdez au pire, quelques secondes de données. Avec Memcache, vous perdez tout.</li>
<li>Memcache possède des fonctionalités de clusterisation que n&#8217;a pas encore Redis, bien que ce soit actuellement en beta.</li>
<li>Redis peut faire bien plus que du stockage clé/valeur.</li>
</ul>
<h2>Redis comme base NoSQL zarbie</h2>
<p>Redis n&#8217;a pas besoin d&#8217;un schéma particulier à définir pour pouvoir sauvegarder ses données, mais n&#8217;est pas pour autant limité à une forme d&#8217;organisation basique. En fait, des types très proches de ceux qu&#8217;on trouve dans le langage Python sont disponibles pour stocker internalement les données, et ils sont <a href="http://redis.io/topics/data-types-intro">décrits dans son excellente doc</a>.</p>
<h3>Liste</h3>
<p>Une <a href="http://redis.io/commands#list">liste</a> est juste une collection ordonnée d&#8217;éléments. On utilise toujours la logique de clé, mais au lieu d&#8217;une valeur, on a une séquence d&#8217;éléments.</p>
<p>Cela permet d&#8217;avoir :</p>
<pre>cle => [
	valeur1,
	valeur2,
	...
]</pre>
<p>Dans le shell :</p>
<pre>127.0.0.1:6379> lpush batman na
(integer) 1
127.0.0.1:6379> lpush batman na
(integer) 2
127.0.0.1:6379> lpush batman na
(integer) 3
127.0.0.1:6379> lpush batman na
(integer) 4
127.0.0.1:6379> lpush batman na
(integer) 5
127.0.0.1:6379> lpush batman na
(integer) 6
127.0.0.1:6379> llen batman
(integer) 6
127.0.0.1:6379> LINDEX batman 3
"na"
127.0.0.1:6379> LINDEX batman 10
(nil)
127.0.0.1:6379> LRANGE batman 0 -1 # du début au dernier élément
1) "na"
2) "na"
3) "na"
4) "na"
5) "na"
6) "na"
127.0.0.1:6379> LRANGE batman 2 3
1) "na"
2) "na"
127.0.0.1:6379></pre>
<p>On peut faire toutes les opérations qu&#8217;on a l&#8217;habitude de faire sur des listes : récupérer un élément, en ajouter un, en retirer un, faire du LIFO, du FIFO, du pipo, etc.</p>
<p>Utile pour créer des files d&#8217;attente, des journaux d&#8217;évènements (pensez jeux vidéos) ou plus simplement une valeur de config plus complexe qu&#8217;une entrée.</p>
<h3>Hash</h3>
<p><a href="http://redis.io/commands#hash">Le Hash</a> se comporte comme un Hash Map, dictionnaire Python, object Javascript, Array associatif en PHP&#8230; Bref, comme Redis lui-même en fait, mais sans expiration de clé. Cela permet d&#8217;avoir :</p>
<pre>cle => {
	cle : valeur,
	cle : valeur,
}</pre>
<p>Dans le shell :</p>
<pre>127.0.0.1:6379> HSET scores titi 1
(integer) 1
127.0.0.1:6379> HSET scores grosminet 0
(integer) 1
127.0.0.1:6379> HSET scores tom 0
(integer) 1
127.0.0.1:6379> HSET scores jerry 1
(integer) 1
127.0.0.1:6379> HGET scores jerry
"1"
127.0.0.1:6379> HGETALL scores
1) "titi"
2) "1"
3) "grosminet"
4) "0"
5) "tom"
6) "0"
7) "jerry"
8) "1"
127.0.0.1:6379></pre>
<p>Notez encore une fois qu&#8217;il n&#8217;est pas utile de vérifier que la clé existe avant de rajouter une valeur dans le hash, bien qu&#8217;il y ait une commande pour le faire. Si on essaye de récupérer une clé qui n&#8217;existe pas, Redis retourne <code>nil</code>.</p>
<p>Le hash est fort pratique pour toute forme de compteurs groupés, ou juste pour mettre en cache des relations. Redis n&#8217;ayant pas de <code>JOIN</code>, on utilise parfois un hash pour faire le lien entre deux listes par exemple.</p>
<h3>Set</h3>
<p>Comme les sets en Python, le <a href="http://redis.io/commands#set">set</a> est une collection NON ordonnée d&#8217;éléments uniques. Il ne peut pas y avoir de doublons dans un set, et vérifier si un élément fait partie d&#8217;un set est une opération très rapide. Ils permettent aussi de faire des opérations ensemblistes de manière performante, par exemple vérifier quels éléments d&#8217;un set sont ou non dans un autre set.</p>
<pre>cle => { valeur1, valeur2, ...}</pre>
<p>Dans le shell :</p>
<pre>127.0.0.1:6379> SADD ip 192.168.1.1
(integer) 1
127.0.0.1:6379> SADD ip 192.168.1.1 # ajouter 2x le même ne fait rien
(integer) 0
127.0.0.1:6379> SADD ip 192.168.1.1
(integer) 0
127.0.0.1:6379> SADD ip 192.168.1.2
(integer) 1
127.0.0.1:6379> SADD ip 192.168.1.3
(integer) 1
127.0.0.1:6379> SCARD ip
(integer) 3
127.0.0.1:6379> SMEMBERS ip
1) "192.168.1.2"
2) "192.168.1.1"
3) "192.168.1.3"
127.0.0.1:6379> SADD ip:banned 192.168.1.3 # le ":" est une séparateur courant pour les clés
(integer) 1
127.0.0.1:6379> SADD ip:banned 192.168.1.10 # ip:banned est un AUTRE set
(integer) 1
127.0.0.1:6379> SINTER ip ip:banned # trouver les IP qui sont dans les 2 sets
1) "192.168.1.3"</pre>
<p>On va utiliser les sets pour éviter les doublons (tirage au sort par exemple) ou pour vérifier facilement une appartenance (notion de groupes, de permissions, etc.).</p>
<p>Le set possède une variante, le <a href="http://redis.io/commands#sorted_set">set ordonné</a>, qui associe à chaque élément du set un score. On peut changer ce score, l&#8217;incrémenter ou le décrémenter atomiquement, avoir deux scores égaux&#8230; Et au final, récupérer le set dans l&#8217;ordre ascendant ou descendant des scores. </p>
<pre>cle => { valeur1 (1), valeur2 (3), ...}</pre>
<p>Dans le shell :</p>
<pre>127.0.0.1:6379> zadd participants 1 staline
(integer) 1
127.0.0.1:6379> zadd participants 1 hitler
(integer) 1
127.0.0.1:6379> zadd participants 2 "pol pot"
(integer) 1
127.0.0.1:6379> zadd participants 1999 "rainbow dash"
(integer) 1
127.0.0.1:6379> zrange participants 0 - 1
(error) ERR value is not an integer or out of range
127.0.0.1:6379> zrange participants 0 -1 
1) "hitler"
2) "staline"
3) "pol pot"
4) "rainbow dash"
127.0.0.1:6379> zrange participants 0 -1 withscores
1) "hitler"
2) "1"
3) "staline"
4) "1"
5) "pol pot"
6) "2"
7) "rainbow dash"
8) "1999"
</pre>
<h3>HyperLogLog</h3>
<p>J&#8217;ai déjà parlé de l&#8217;HyperLogLog <a href="http://sametmax.com/le-compteur-mal-connu-lhyperloglog/">ici</a> et <a href="http://redis.io/commands#hyperloglog">celui de Redis</a> fonctionne pareil. Cette structure de données permettra de faire des compteurs d&#8217;éléments uniques, comme par exemple un compteur de visiteurs ou de gens connectés, qui soit approximatif (+ ou &#8211; 1%) mais prenne une taille fixe en mémoire.</p>
<p>Dans le shell :</p>
<pre>127.0.0.1:6379> PFADD connectes toto
(integer) 1
127.0.0.1:6379> PFADD connectes toto
(integer) 0
127.0.0.1:6379> PFADD connectes toto
(integer) 0
127.0.0.1:6379> PFADD connectes tata
(integer) 1
127.0.0.1:6379> PFADD connectes titi
(integer) 1
127.0.0.1:6379> PFADD connectes tutu
(integer) 1
127.0.0.1:6379> PFADD connectes tutu
(integer) 0
127.0.0.1:6379> PFADD connectes tutu
(integer) 0
127.0.0.1:6379> PFADD connectes tete
(integer) 1
127.0.0.1:6379> PFADD connectes bob
(integer) 1
127.0.0.1:6379> PFcount connectes
(integer) 6
127.0.0.1:6379>
</pre>
<h2>Redis comme super pote de Python</h2>
<p>Vu que Redis est simple à installer et à configurer, c&#8217;est un outil qu&#8217;on dégaine facilement, même pour un petit script, pas forcément pour une grosse app Web. Par exemple, je fais une analyse de mon serveur, plutôt que de stocker le résultat dans un fichier, je peux mettre tout ça dans Redis, c&#8217;est tellement pratique.</p>
<p>D&#8217;abord, la <a href="https://pypi.python.org/pypi/redis/">lib</a> pour communiquer avec Redis est à un <a href="http://sametmax.com/votre-python-aime-les-pip/">pip</a> du clavier :</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> redis</pre></td></tr></table></div>

<p>Ensuite, si vous utilisez le client <code>StrictRedis</code>, l&#8217;API est exactement la même que les commandes du shell :</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> redis
<span style="color: #66cc66;">&gt;&gt;&gt;</span> r <span style="color: #66cc66;">=</span> redis.<span style="color: black;">StrictRedis</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> r.<span style="color: black;">hgetall</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'scores'</span><span style="color: black;">&#41;</span>
<span style="color: black;">&#123;</span>b<span style="color: #483d8b;">'titi'</span>: b<span style="color: #483d8b;">'1'</span><span style="color: #66cc66;">,</span> b<span style="color: #483d8b;">'tom'</span>: b<span style="color: #483d8b;">'0'</span><span style="color: #66cc66;">,</span> b<span style="color: #483d8b;">'jerry'</span>: b<span style="color: #483d8b;">'1'</span><span style="color: #66cc66;">,</span> b<span style="color: #483d8b;">'grosminet'</span>: b<span style="color: #483d8b;">'0'</span><span style="color: black;">&#125;</span></pre></td></tr></table></div>

<p>Il existe aussi des drivers asynchrones pour tornado, twisted et asyncio.</p>
<h2>Redis comme message broker</h2>
<p>J&#8217;aime le <a href="http://redis.io/commands#pubsub">pub/sub</a>, je pense qu&#8217;après mon <a href="http://sametmax.com/introduction-a-wamp-en-python/">enthousiasme</a> pour WAMP.ws, c&#8217;est clair.</p>
<p>Redis met à disposition des primitives pour créer des files d&#8217;attente de messages et les lire, comme une version simplifiée de RabbitMQ ou Crossbar.io. Pour que ce soit intéressant, il nous faut deux process. D&#8217;abord un shell Python qui écoute les messages arrivant sur la file &#8220;sametmax&#8221; :</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> redis
<span style="color: #66cc66;">&gt;&gt;&gt;</span> r <span style="color: #66cc66;">=</span> redis.<span style="color: black;">StrictRedis</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> listener <span style="color: #66cc66;">=</span> r.<span style="color: black;">pubsub</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> listener.<span style="color: black;">subscribe</span><span style="color: black;">&#40;</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">'sametmax'</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">for</span> item <span style="color: #ff7700;font-weight:bold;">in</span> listener.<span style="color: black;">listen</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>item<span style="color: black;">&#41;</span>
...</pre></td></tr></table></div>

<p>Le code va bloquer, et affichera quelque chose à chaque fois qu&#8217;il reçoit un message.</p>
<p>Du coup si je fais ceci dans le shell Redis :</p>
<pre>127.0.0.1:6379> publish sametmax yolo
(integer) 1
127.0.0.1:6379> publish sametmax carpediem
(integer) 1
127.0.0.1:6379> publish sametmax wololo
(integer) 1
127.0.0.1:6379> publish sametmax2 oyooyo
(integer) 0
127.0.0.1:6379></pre>
<p>Mon shell python va afficher :</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;">'type'</span>: <span style="color: #483d8b;">'subscribe'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'pattern'</span>: <span style="color: #008000;">None</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'channel'</span>: b<span style="color: #483d8b;">'sametmax'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'data'</span>: <span style="color: #ff4500;">1</span><span style="color: black;">&#125;</span>
<span style="color: black;">&#123;</span><span style="color: #483d8b;">'type'</span>: <span style="color: #483d8b;">'message'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'pattern'</span>: <span style="color: #008000;">None</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'channel'</span>: b<span style="color: #483d8b;">'sametmax'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'data'</span>: b<span style="color: #483d8b;">'yolo'</span><span style="color: black;">&#125;</span>
<span style="color: black;">&#123;</span><span style="color: #483d8b;">'type'</span>: <span style="color: #483d8b;">'message'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'pattern'</span>: <span style="color: #008000;">None</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'channel'</span>: b<span style="color: #483d8b;">'sametmax'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'data'</span>: b<span style="color: #483d8b;">'carpediem'</span><span style="color: black;">&#125;</span>
<span style="color: black;">&#123;</span><span style="color: #483d8b;">'type'</span>: <span style="color: #483d8b;">'message'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'pattern'</span>: <span style="color: #008000;">None</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'channel'</span>: b<span style="color: #483d8b;">'sametmax'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'data'</span>: b<span style="color: #483d8b;">'wololo'</span><span style="color: black;">&#125;</span></pre></td></tr></table></div>

<p>Il n&#8217;a pas affiché <code>oyooyo</code> puisque c&#8217;est sur une autre channel.</p>
<p>C&#8217;est une méthode assez simple de faire du pub/sub. C&#8217;est bas niveau, il n&#8217;y a pas de RPC, il faut boucler à la main et créer soit-même la mécanique pour arrêter d&#8217;écouter ou faire du multitask, mais c&#8217;est facile pour débuter. Pour cette raison, plein de gens utilisent une solution bricolée là-dessus pour faire du pub/sub.</p>
<h2>Et donc</h2>
<p>Non seulement Redis est facile à installer, simple à utiliser et performant, mais en plus il est accessible depuis de nombreux langages. Ajoutez à cela ses très nombreuses fonctionnalités, et vous avez là un système qui est installé par défaut sur la plupart de mes serveurs. Par ailleurs, suivez <a href="http://antirez.com/latest/0">le blog de l&#8217;auteur</a>, ce mec est un génie. Il écrit pas souvent, mais quand il écrit, c&#8217;est passionant, et humble. C&#8217;est beau.</p>


feed_id: http://sametmax.com/?p=12424
title: Django pleure ‘MySQL server has gone away’
uri: Django-pleure-MySQL-server-has-gone-away
url: http://sametmax.com/django-pleure-mysql-server-has-gone-away/
content:
<p>Dans certaines circonstances, par exemple une transaction ouverte pendant trop longtemps, MySQL ferme la connexion avec son client. </p>
<p>Cela arrive par exemple quand on l&#8217;utilise comme broker pour celery. On a des tâches qui plantent, et quand on met du debug, on lit un <code>(2006, 'MySQL server has gone away')</code> bien cryptique.</p>
<p>Généralement je recommande de changer de backend ici. Passer à redis pour cet usage par exemple.</p>
<p>Mais parfois on ne peut pas. La solution est alors de forcer Django à réinitialiser la connexion en la fermant. Il faut le faire au niveau où on a remarqué que la requête échouait. Dans notre cas, au début de chaque tâche celery :</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;">db</span> <span style="color: #ff7700;font-weight:bold;">import</span> connection 
&nbsp;
<span style="color: #66cc66;">@</span>task
<span style="color: #ff7700;font-weight:bold;">def</span> do_stuff<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    connection.<span style="color: black;">close</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    <span style="color: #808080; font-style: italic;"># le reste du code</span></pre></td></tr></table></div>

<p>Voyant la connexion fermée, Django va en ouvrir une nouvelle à la prochaine requête automatiquement.</p>
<p>Cela a, évidement, un impact sur les performances, donc choisissez bien entre mettre une rustine et changer la roue.</p>


feed_id: http://sametmax.com/?p=12406
title: Est-ce la fin de jQuery ?
uri: Est-ce-la-fin-de-jQuery
url: http://sametmax.com/est-ce-la-fin-de-jquery/
content:
<p>Avec un report massif des usagers sur des mobiles, la plupart sous un navigateur Webkit powered, on peut tabler sur un bien meilleur support de Javascript et ses APIs. Cela signifie qu&#8217;on a moins besoin d&#8217;utiliser des libs pour combler les trous, mais aussi la possibilité d&#8217;utiliser des frameworks comme AngularJS, MeteorJS, etc.</p>
<p>Est-ce pour autant la fin de notre bien aimé jQuery, qui nous a sorti de l&#8217;age sombre, et nous a tenu la main pendant cette dernière décénnie ?</p>
<p>Non.</p>
<p>Bien entendu, on utilise moins jQuery. On utilise parfois des choses plus légères. Parfois des choses plus lourdes. Parfois du JS pur. </p>
<p>Et il faut avouer que les projets parallèles à jQuery comme jQuery Mobile et jQueryUI n&#8217;ont jamais décollé. Merci Bootstrap et le responsive design.</p>
<p>Néanmoins, il reste des tas de choses pour lesquelles jQuery est utile.</p>
<p>Certes, il y a les versions light qui font &#8220;presque la même chose mais avec beaucoup moins de ko&#8221;. Mais c&#8217;est le &#8220;presque&#8221; qui finit par vous faire ajouter plein d&#8217;autres dépendances, pour finalement vous retrouver avec un truc qui fait &#8220;presque&#8221; la même taille que la lib que vous vouliez éviter, et qui ne sera probablement pas en cache. De plus, la documentation disponible n&#8217;est pas du tout comparable.</p>
<p>Et certes, il y a les outils bazooka, qui font tout, même le café. Mais les solutions comme Angular ne permettent pas une dégradation gracieuse du site, pèchent en référencement, et massacrent l&#8217;accessibilité. Les apps sont des bons candidats pour une &#8220;one page navigation&#8221;, mais pas les sites orientés contenus, quant aux hybrides&#8230;</p>
<p>Pensez aussi que même si vous codez pour des browsers modernes (donc pas IE8 qui limite ses sélecteurs à css 2.1), les APIs haut niveau comme <code>querySelector</code> et <code>querySelectorAll</code> sont très loin d&#8217;être aussi pratiques et puissantes que le bon vieux <code>$()</code>. Je ne parle même pas de la gestion des événements et d&#8217;Ajax qui sont toujours à chier en 2014.</p>
<p>Donc jQuery permet de rajouter cette petite touche de dynamisme à votre site statique, ou de faire un outil moderne sans sacrifier les aveugles et le PR. C&#8217;est un compromis entre puissance et simplicité. Et quand vous sortirez du cas standard, contrairement aux versions au bifidus actif allégé, la lib vous permettra de sauter le pas avec ses centaines de features, ou ses milliers de plugins.</p>
<p>Sans compter l&#8217;immense base de projets existants utilisant le bouzin, et qu&#8217;il va bien falloir maintenir. Bonne chance à ceux qui veulent porter un site avec jQuery vers un autre truc. N&#8217;oubliez pas non plus l&#8217;inertie technique. Et le temps de formation de la population de dev aux nouvelles technos. Surtout qu&#8217;en ce moment, avec l&#8217;avalanche de nouveaux trucs à tester/apprendre/valider, il va falloir gérer ses priorités. Ajoutez à ça la baisse drastique du niveau des devs sur le marché du travail :)</p>
<p>Bref, bien que j&#8217;apprécie et utilise les nombreuses alternatives à jQuery, il  ne va pas disparaitre cette année, et probablement pas l&#8217;année prochaine.</p>


feed_id: http://sametmax.com/?p=12400
title: Pas Hexactement
uri: Pas-Hexactement
url: http://sametmax.com/pas-hexactement/
content:
<p>Je préfère utiliser le terme francophone que français pour le public du blog. D&#8217;ailleurs, quand je retweet des offres d&#8217;emploi, je le fais pour les pays limitrophes à la France, et également le Canada ou l&#8217;Afrique du Nord et de l&#8217;Ouest.</p>
<p>Ce n&#8217;est pas un hasard. En effet, si on regarde les stats du blog :</p>
<pre>France 	5,135
Belgium 	302
Canada 	130
Switzerland 	129
United States  States	105
Luxembourg 	64
Tunisia 	44
United Kingdom  Kingdom	40
Bulgaria 	39
New Caledonia	33
Algeria 	32
Réunion 	28
Morocco 	24</pre>
<p>302 + 130 + 129 + 64 + 32 + 24 = 681 vues qui viennent de pays francophones, soit plus de 10 %. Le français est beaucoup plus parlé dans le monde qu&#8217;on ne le croit. Sans parler des expats, évidement.</p>
<p>Donc à tout ceux qui ne sont pas de l&#8217;hexagone, coucou !</p>
<p>Je suis assez épaté du chiffre Bulgare ceci dit. </p>


feed_id: http://sametmax.com/?p=12464
title: Ceci n’est pas une pipe
uri: Ceci-n-est-pas-une-pipe
url: http://sametmax.com/ceci-nest-pas-une-pipe/
content:
<p>Ni un forum. Ni un chan IRC. C&#8217;est un blog.</p>
<p>Pour cette raison, il est inutile de demander de l&#8217;aide en commentaire. Faites-le dans un endroit qui est adapté pour cela.</p>
<p>Exemple, pour Python :</p>
<ul>
<li><a href="http://www.afpy.org/forums/forum_python">Forum de l&#8217;afpy</a></li>
<li><a href="http://www.developpez.net/forums/f96/autres-langages/python-zope/">Forum de developpez.com</a></li>
<li><a href="http://fr.openclassrooms.com/forum/categorie/langage-python">Forum d&#8217;openclassroom</a></li>
<li><a href="http://forum.hardware.fr/hfr/Programmation/Python/liste_sujet-1.htm">Forum de hardware.fr</a></li>
<li>News group Python fr : news:fr.comp.lang.python </li>
</ul>
<p>Un commentaire se doit d&#8217;être en lien avec l&#8217;article posé, ou un autre commentaire. La seule exception est pour les anciens du blog, qui ont carte blanche car ils ont participé à la création de la communauté, et c&#8217;est un peu chez eux.</p>
<p>Abordons maintenant le point délicat du formulaire de contact. Il peut servir à poser des questions qui ne sont pas liées à un article, pourvu que :</p>
<ul>
<li>Ce ne soit pas un débat.</li>
<li>Ce ne soit pas une demande de dépannage.</li>
</ul>
<p>Si vous ne le faites pas et que je suis de mauvais poil, la réponse risque de ne pas être celle attendue. Pour vous donner un exemple, voici cet article tel que je l&#8217;aurais écrit un jour grincheux :</p>
<blockquote><p>Ceci n&#8217;est pas une pipe</p>
<p>Ni un forum. Ni un chan IRC. C&#8217;est un blog.</p>
<p>Si vous avez une question posez la plutôt sur un forum d&#8217;entre-aide, vous aurez une chance d&#8217;avoir une réponse, et vous nous éviterez de vous ajouter à la liste des milliers de personnes qui nous ont fait perdre du temps avant vous.</p>
<p>Car oui vous êtes le 9878eme, non, on ne vous doit rien, et enfin, ce blog demande des centaines d&#8217;heures de travail par mois. Bref, on a pas que ça à foutre de vous modérer parce que vous n&#8217;avez pas eu la politesse de vous sortir les doigts du cul pour faire une recherche sur google et trouver un endroit qui est FAIT pour poser des questions.</p>
<p>Exemple, pour Python :</p>
<p>http://www.afpy.org/forums/forum_python&#8221;>Forum de l&#8217;afpy<br />
http://www.developpez.net/forums/f96/autres-langages/python-zope/&#8221;>Forum de devloppez.com<br />
http://fr.openclassrooms.com/forum/categorie/langage-python&#8221;>Forum d&#8217;openclassroom<br />
http://forum.hardware.fr/hfr/Programmation/Python/liste_sujet-1.htm&#8221;>Forum de hardware.fr</p>
<p>Oua, ça m&#8217;a pris 10 minutes pour trouver ces liens, et ce n&#8217;est QUE la partie fr.</p>
<p>Si vous n&#8217;êtes pas foutu de bouger votre fion pour trouver ces endroits, sérieusement, pourquoi voudriez-vous que je frémisse le petit doigt pour votre tronche de feignasse ?</p>
<p>Et si vous vous demandez pourquoi le ton de l&#8217;article est agressif, c&#8217;est parce que la masse de connards passifs me casse les couilles, et que si j&#8217;ai posté le lien, vous en faites partie.
</p></blockquote>
<p>Vous comprenez donc qu&#8217;il est préférable de garder cet espace joyeux, libre de haine et plein d&#8217;arc-en-ciels dans le cœur.</p>
<p>Sauvez un chaton, écrivez vos demandes d&#8217;aide sur un forum.</p>


feed_id: http://sametmax.com/?p=12456
title: Appliquer un traitement à tous les fichiers d’un dossier en Python
uri: Appliquer-un-traitement-à-tous-les-fichiers-d-un-dossier-en-Python
url: http://sametmax.com/appliquer-un-traitement-a-tous-les-fichiers-dun-dossier-en-python/
content:
<p>Opération courante en informatique et on a tous eu besoin de chercher comment faire une fois.</p>
<p>Soit l’arborescence :</p>
<pre>test
├── dossier
│   ├── fichier.py
│   ├── fichier.txt
│   └── pas_un_dossier.txt
├── Dossier
│   ├── dOssier
│   │   └── faichier
│   └── fichiiiiiiiiier
├── .fichier
├── fichier
├── fIchier
└── Fichier
</pre>
<h2>Lister le contenu d&#8217;un dossier</h2>

<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;">os</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #dc143c;">os</span>.<span style="color: black;">listdir</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'.'</span><span style="color: black;">&#41;</span>
<span style="color: black;">&#91;</span><span style="color: #483d8b;">'dossier'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'Dossier'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'fichier'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'fIchier'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'.fichier'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'Fichier'</span><span style="color: black;">&#93;</span></pre></td></tr></table></div>

<p>On récupère les noms des dossiers et les fichiers, y compris cachés, mais pas les dossiers spéciaux types <code>..</code> et <code>.</code>.</p>
<p>Le type des noms retournés est <code>str</code> que ce soit en Python 2 ou 3. Ça a l&#8217;air cool et homogène comme ça, jusqu&#8217;à ce qu&#8217;on se souvienne que <code>str</code> sont des bits en Python 2 et de l&#8217;unicode en Python 3. Donc gaffe quand vous portez votre code d&#8217;une version à l&#8217;autre. Les noms de fichiers contiennent des caractères non ASCII dans la vraie vie vivante.</p>
<p>Si vous voulez récupérer uniquement les dossiers ou les fichiers, il va falloir filtrer :</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;">for</span> element <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #dc143c;">os</span>.<span style="color: black;">listdir</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'/tmp/test'</span><span style="color: black;">&#41;</span>:
...     <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">isdir</span><span style="color: black;">&#40;</span>element<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;'%s' un dossier&quot;</span> % element<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;">&quot;'%s' est un fichier&quot;</span> % element<span style="color: black;">&#41;</span>
<span style="color: #483d8b;">'dossier'</span> un dossier
<span style="color: #483d8b;">'Dossier'</span> un dossier
<span style="color: #483d8b;">'fichier'</span> est un fichier
<span style="color: #483d8b;">'fIchier'</span> est un fichier
<span style="color: #483d8b;">'.fichier'</span> est un fichier
<span style="color: #483d8b;">'Fichier'</span> est un fichier</pre></td></tr></table></div>

<p>Pareil si on veut filtrer par extensions :</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;">for</span> element <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #dc143c;">os</span>.<span style="color: black;">listdir</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'/tmp/test/dossier'</span><span style="color: black;">&#41;</span>:
...     <span style="color: #ff7700;font-weight:bold;">if</span> element.<span style="color: black;">endswith</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'.txt'</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;'%s' est un fichier texte&quot;</span> % element<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;">&quot;'%s' n'est pas un fichier texte&quot;</span> % element<span style="color: black;">&#41;</span>
<span style="color: #483d8b;">'fichier.txt'</span> est un fichier texte
<span style="color: #483d8b;">'pas_un_dossier.txt'</span> est un fichier texte
<span style="color: #483d8b;">'fichier.py'</span> n<span style="color: #483d8b;">'est pas un fichier texte</span></pre></td></tr></table></div>

<p>Néanmoins, Python vient avec le module <code>glob</code> qui permet de demander le listing du contenu d&#8217;un dossier en appliquant des filtres Unix :</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;">glob</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #dc143c;">glob</span>.<span style="color: #dc143c;">glob</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'/tmp/test/dossier/*.txt'</span><span style="color: black;">&#41;</span>
<span style="color: black;">&#91;</span><span style="color: #483d8b;">'/tmp/test/dossier/fichier.txt'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'/tmp/test/dossier/pas_un_dossier.txt'</span><span style="color: black;">&#93;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #dc143c;">glob</span>.<span style="color: #dc143c;">glob</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'./dossier/*.txt'</span><span style="color: black;">&#41;</span>
<span style="color: black;">&#91;</span><span style="color: #483d8b;">'./dossier/fichier.txt'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'./dossier/pas_un_dossier.txt'</span><span style="color: black;">&#93;</span></pre></td></tr></table></div>

<p>Mais comme vous pouvez le voir, le comportement n&#8217;est pas le même que <code>listdir</code> : les éléments de la liste sont des chemins relatifs à celui passé en paramètre si il est lui-même relatif, ou absolus si celui passé en paramètre est absolu. N&#8217;oubliez donc pas de normaliser l&#8217;entrée ou la sortie avec <code>os.path.realpath</code> qui retournera un chemin canonique.</p>
<p>Même problème Python 2/3 : le type est <code>str</code> dans les 2 cas. </p>
<h2>Parcours récursif</h2>
<p>La fonction <code>os.walk</code> permet de lister récursivement tous les fichiers et les dossiers à partir d&#8217;un point dans l&#8217;arborescence. C&#8217;est un générateur, et sa valeur de retour est un peu particulière et se récupère via <a href="http://sametmax.com/tag/unpacking/">unpacking</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> dossier<span style="color: #66cc66;">,</span> sous_dossiers<span style="color: #66cc66;">,</span> fichiers <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #dc143c;">os</span>.<span style="color: black;">walk</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'/tmp/test'</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;">'##### %s #####'</span> % dossier<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;Sous dossiers : %s&quot;</span> % sous_dossiers<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;Fichiers : %s&quot;</span> % fichiers<span style="color: black;">&#41;</span>
<span style="color: #808080; font-style: italic;">##### /tmp/test #####</span>
Sous dossiers : <span style="color: black;">&#91;</span><span style="color: #483d8b;">'dossier'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'Dossier'</span><span style="color: black;">&#93;</span>
Fichiers : <span style="color: black;">&#91;</span><span style="color: #483d8b;">'fichier'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'fIchier'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'.fichier'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'Fichier'</span><span style="color: black;">&#93;</span>
<span style="color: #808080; font-style: italic;">##### /tmp/test/dossier #####</span>
Sous dossiers : <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>
Fichiers : <span style="color: black;">&#91;</span><span style="color: #483d8b;">'fichier.txt'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'pas_un_dossier.txt'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'fichier.py'</span><span style="color: black;">&#93;</span>
<span style="color: #808080; font-style: italic;">##### /tmp/test/Dossier #####</span>
Sous dossiers : <span style="color: black;">&#91;</span><span style="color: #483d8b;">'dOssier'</span><span style="color: black;">&#93;</span>
Fichiers : <span style="color: black;">&#91;</span><span style="color: #483d8b;">'fichiiiiiiiiier'</span><span style="color: black;">&#93;</span>
<span style="color: #808080; font-style: italic;">##### /tmp/test/Dossier/dOssier #####</span>
Sous dossiers : <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>
Fichiers : <span style="color: black;">&#91;</span><span style="color: #483d8b;">'faichier'</span><span style="color: black;">&#93;</span></pre></td></tr></table></div>

<p>Du coup, si vous voulez avoir la liste des chemin des fichiers absolus, il faut reconstituer à la main :</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> dossier<span style="color: #66cc66;">,</span> sous_dossiers<span style="color: #66cc66;">,</span> fichiers <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #dc143c;">os</span>.<span style="color: black;">walk</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'/tmp/test'</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">for</span> fichier <span style="color: #ff7700;font-weight:bold;">in</span> fichiers:
        <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">join</span><span style="color: black;">&#40;</span>dossier<span style="color: #66cc66;">,</span> fichier<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
/tmp/<span style="color: #dc143c;">test</span>/fichier
/tmp/<span style="color: #dc143c;">test</span>/fIchier
/tmp/<span style="color: #dc143c;">test</span>/.<span style="color: black;">fichier</span>
/tmp/<span style="color: #dc143c;">test</span>/Fichier
/tmp/<span style="color: #dc143c;">test</span>/dossier/fichier.<span style="color: black;">txt</span>
/tmp/<span style="color: #dc143c;">test</span>/dossier/pas_un_dossier.<span style="color: black;">txt</span>
/tmp/<span style="color: #dc143c;">test</span>/dossier/fichier.<span style="color: black;">py</span>
/tmp/<span style="color: #dc143c;">test</span>/Dossier/fichiiiiiiiiier
/tmp/<span style="color: #dc143c;">test</span>/Dossier/dOssier/faichier</pre></td></tr></table></div>

<p>Encore une fois, c&#8217;est du <code>str</code> partout, alors attention. L&#8217;article sur l&#8217;<a href="http://sametmax.com/lencoding-en-python-une-bonne-fois-pour-toute/">encoding en Python </a>reste un des plus consultés de la categ prog.</p>
<h2>Avec une lib qui va bien</h2>
<p>Je n&#8217;ai jamais caché mon amour immodéré pour <a href="https://pythonhosted.org/path.py/api.html">path.py</a> (qui enterre tous ses concurrents, dont unipath), qui encapsule toutes les opérations des fichiers de manière simple et élégante et qui marche sous 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> path.py</pre></td></tr></table></div>

<p>Et c&#8217;est quand même plus facile pour le parcours récursif :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">from</span> path <span style="color: #ff7700;font-weight:bold;">import</span> path
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">for</span> f <span style="color: #ff7700;font-weight:bold;">in</span> path<span style="color: black;">&#40;</span><span style="color: #483d8b;">'.'</span><span style="color: black;">&#41;</span>.<span style="color: black;">walkfiles</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">print</span> f
   ....:     
./dossier/fichier.<span style="color: black;">txt</span>
./dossier/pas_un_dossier.<span style="color: black;">txt</span>
./dossier/fichier.<span style="color: black;">py</span>
./Dossier/fichiiiiiiiiier
./Dossier/dOssier/faichier
./fichier
./fIchier
./.<span style="color: black;">fichier</span>
./Fichier</pre></td></tr></table></div>

<p>En plus, <code>f</code> est de type <code>path</code> sous Python 2 et 3. C&#8217;est homogène, et ça permet de faire toutes les opérations magiques que ce type permet.</p>
<p>Néanmoins, si vous êtes sous Python 3.4 et que vous ne voulez pas ajouter une dépendance externe, vous pouvez utiliser le module <a href="https://docs.python.org/3/library/pathlib.html">pathlib</a> :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">from</span> pathlib <span style="color: #ff7700;font-weight:bold;">import</span> Path
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">for</span> p <span style="color: #ff7700;font-weight:bold;">in</span>  Path<span style="color: black;">&#40;</span><span style="color: #483d8b;">'.'</span><span style="color: black;">&#41;</span>.<span style="color: #dc143c;">glob</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'./**/*'</span><span style="color: black;">&#41;</span>:
...    <span style="color: #ff7700;font-weight:bold;">if</span> p.<span style="color: black;">is_file</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>p<span style="color: black;">&#41;</span>
fichier
fIchier
.<span style="color: black;">fichier</span>
Fichier
dossier/fichier.<span style="color: black;">txt</span>
dossier/pas_un_dossier.<span style="color: black;">txt</span>
dossier/fichier.<span style="color: black;">py</span>
Dossier/fichiiiiiiiiier
Dossier/dOssier/faichier</pre></td></tr></table></div>


feed_id: http://sametmax.com/?p=12476
title: Comment écrire une annonce pour recruter des dev
uri: Comment-écrire-une-annonce-pour-recruter-des-dev
url: http://sametmax.com/comment-ecrire-une-annonce-pour-recruter-des-dev/
content:
<p>Je critique souvent les offres d&#8217;emploi, mais l&#8217;art est difficile, alors voici quelques lignes directrices si cela vous arrive un jour.</p>
<h2>Ne mettez pas les RH en avant</h2>
<p>Les RH ne doivent PAS rédiger l&#8217;annonce. Le moyen de contact ne doit PAS être celui des RH.</p>
<p>Je ne dis pas que les RH ne doivent pas faire partie du processus de recrutement. Mais je recommande qu&#8217;ils s&#8217;en tiennent à l&#8217;administratif et à l&#8217;accompagnement de l&#8217;équipe technique dans la démarche.</p>
<p>Ils ne sont tout simplement pas qualifiés pour ça.</p>
<p>Ce n&#8217;est pas une insulte, c&#8217;est un constat que je fais tous les jours. Ils ne sont pas capables d&#8217;évaluer un profil technique correctement. Ils recalent trop facilement de bons profils pour délit de sale gueule (courant en info). Ils ne savent pas lire un CV tech, ils vont juste comparer les besoins de l&#8217;annonce avec le papier.</p>
<p>Mettez les membres de l&#8217;équipe qui va accueillir la recrue comme contact, et demandez leur de rédiger l&#8217;annonce.</p>
<p>Cela a de nombreux avantages :</p>
<ul>
<li>Ils se sentent valorisés.</li>
<li>Ils sont impliqués dans le choix de leur collègue, l&#8217;intégration sera meilleure.</li>
<li>Ils peuvent voir des choses lors de l&#8217;entretien ou sur un CV qui sort du lot même si ça ne rentre pas dans des cases.</li>
<li>Ils ne vont pas écrire n&#8217;importe quoi dans l&#8217;annonce. Sérieux, quand je lis MailleSQL dans une annonce, j&#8217;ai envie de fesser les responsables.</li>
<li>C&#8217;est moins intimidant pour la personne qui répond à l&#8217;annonce. Parler à quelqu&#8217;un de son métier met à l&#8217;aise, et incite à postuler. Les dev sont parfois peu sociables, il faut leur faciliter cette démarche.</li>
</ul>
<p>Bien entendu, il est important que les RH les accompagnent dans le processus. Les techos n&#8217;y connaissent rien en recrutement. C&#8217;est un travail d&#8217;équipe. Mais ils doivent être ce qui est mis en avant, le premier filtre, et le dernier mot.</p>
<h2>Les infos importantes</h2>
<p>Trop souvent je vois des annonces qui ne listent pas les infos essentielles. Voici une liste des choses qui DOIVENT figurer sur l&#8217;annonce :</p>
<ul>
<li>Moyen de contact par email ET par téléphone. Nom de la personne qui va répondre, et poste.</li>
<li>Missions principales en 3 points : le sujet sur lequel on va travailler, quel rôle on va jouer, et les technos utilisées.</li>
<li>Talents requis, humains et techniques.</li>
<li>Échelle de rémunération.</li>
<li>Conditions de travail : équipe que l&#8217;on va intégrer (taille et rôle), localisation géographique du bureau, télétravail possible, etc.</li>
<li>Repères temporels : date de l&#8217;annonce, date de recrutement souhaitée, durée du contrat.</li>
</ul>
<p>A l&#8217;inverse, supprimez le bruit : expressions à la mode, jargon corporate, formules toutes faites&#8230; Les devs sont sensibles à ce genre de chose, et il est facile de passer pour des charlots en voulant rajouter du nutella sur la confiture.</p>
<p>Les trucs à oublier :</p>
<ul>
<li>&#8220;leader du marché&#8221;, &#8220;en forte croissance&#8221;, et toute autre auto congratulation. On s&#8217;en branle.</li>
<li>&#8220;projet innovant&#8221;, &#8220;révolutionner&#8221;, &#8220;so excited&#8221; et autres promesses que vous n&#8217;êtes pas capable de tenir. L’enthousiasme, vous le communiquez à l&#8217;entretien. Là ça fait vendeur de tapis Apple.</li>
<li>&#8220;vous êtes passionnés&#8221;, &#8220;un ninja&#8221;, &#8220;un killer&#8221;. Vous recruteriez quelqu&#8217;un pour la compta, vous diriez ça franchement ?</li>
<li>Les termes vagues : &#8220;taille humaine&#8221; (donnez un nombre), &#8220;réactifs aux changements&#8221; (ça veut tout et rien dire), &#8220;challenge&#8221; (listez les défis, ne les qualifiez pas).</li>
</ul>
<p>Évitez que votre annonce ressemble à <a href="http://sametmax.com/les-annonces-hypes/">ça</a>.</p>
<h2>Soyez pragmatique</h2>
<p>Tous les parents trouvent qu&#8217;ils ont le plus beau bébé du monde, mais ils vous les cassent quand ils vous montrent les photos en vous clamant qu&#8217;il est fantastique.</p>
<p>Votre boîte pète peut-être du Chanel numéro 5 à vos yeux, mais à moins d&#8217;avoir une attractivité incroyable (auquel cas vous n&#8217;avez probablement pas besoin de mettre une annonce), tout le monde s&#8217;en fout.</p>
<p>Bref, n’exigez pas un bac+x pour votre poste, il n&#8217;en a très probablement pas besoin. Mettez uniquement les talents requis techniques et humains. Ceux indispensables. Oubliez la limite d&#8217;âge, de diplôme et autres caractéristiques purement sociétales.</p>
<p>La seule chose qui compte, c&#8217;est que le mec fasse son job, et ça, il n&#8217;y a qu&#8217;un moyen de le vérifier : le voir bosser. Donc préparez des tests techniques, et organisez la période d&#8217;essai. Souvenez-vous qu&#8217;un gars débrouillard se formera sur le tas sans problème en info, c&#8217;est l&#8217;essence de notre taff.</p>
<p>Enfin, si vous voulez un mec bon, il va falloir se montrer attractif. On lui proposera 80k à Londres pour le même poste, trouvez un moyen de matcher ça.</p>
<p>Et si vous voulez un crack, souvenez-vous qu&#8217;il peut avoir 200k aux US. Le fait qu&#8217;il soit en France montre qu&#8217;il est intéressé par autre chose que l&#8217;argent. Cherchez ce que c&#8217;est, et tentez de devenir attractif en rapport avec ce point. Il y a bien d&#8217;autres choses que du pognon : télétravail, horaires flexibles, matériel de qualité, aide pour la famille s&#8217;il a des mômes, responsabilités inhabituelles pour quelqu&#8217;un d&#8217;aussi jeune, etc.</p>
<p>Mais la plupart du temps <strong>vous n&#8217;avez pas besoin d&#8217;un tueur</strong>. Vous avez besoin d&#8217;un mec normal, qui fait son boulot normalement. Alors ne faites pas votre processus de recrutement comme si vous cherchiez le prochain Linus Torvalds. Soyez réaliste, et vous trouverez plus rapidement ce dont vous avez besoin.</p>
<p>Je ne veux pas dire qu&#8217;il faut recruter n&#8217;importe quel boulet. Mettez les (nombreux) incompétents de côté rapidement, et efficacement, sans remord. Néanmoins, descendez de vos grands chevaux. Trop de recruteurs visent bien plus haut que ce dont ils ont besoin, mais aussi de ce qu&#8217;ils valent. Et de ce qu&#8217;ils peuvent payer.</p>
<p>L&#8217;offre et la demande ne sont pas en votre faveur, et ça ne va pas s&#8217;améliorer. Je vois tous les jours les résultats désastreux de mauvaises embauches, si vous voulez éviter ça, il faut se remettre en question.</p>
<h2>Exemple</h2>
<blockquote><p>Cherche Dev Backend Python</p></blockquote>
<p>Titre simple, court, qui permet d&#8217;être scanné facilement. Votre annonce ne sera pas lue par 99% des chercheurs, elle sera listée sur une page au milieu de centaines d&#8217;autres. Pour cette raison, mettez des mots-clés qui permettent facilement de la lister. &#8220;cherche&#8221;, &#8220;dev&#8221; et &#8220;python&#8221; font une query simple pour Google, Twitter, ou le meta moteur des sites de jobs.</p>
<blockquote><p>
Mon équipe de 3 dev a besoin d&#8217;un(e) pythonista pour travailler sur notre crawler de pages. La mission sera dans un premier temps de rajouter de nouvelles sources d&#8217;information à parser. Cela inclut une batterie de tests et de la documentation. D&#8217;autres tâches ponctuelles comme de la correction de bugs de notre ancien système et de la refactorisation des précédents crawlers sont à prévoir.
</p></blockquote>
<p>On commence par le quoi. C&#8217;est ce qui intéresse le plus la recrue, il veut savoir ce qu&#8217;il va foutre là-bas. Pas besoin de rentrer dans trop de détails, il faut juste en donner assez pour être clair, et pas trop pour l&#8217;inciter à appeler pour en savoir plus.</p>
<p>On utilise la première personne, ce qui donne un sentiment de proximité. &#8220;pythonista&#8221; est un terme spécifique à ce type de dev, montrant que l&#8217;annonce a été rédigée par quelqu&#8217;un qui s&#8217;y connaît.</p>
<blockquote><p>
Nous : LambdaBoite est spécialisée dans la vente de LambdaProduit, notre but étant de satisfaire LambdaBesoin de LambdaTypeDeClient.</p>
<p>Vous : on se fiche de savoir si vous avez 23 ans, portez des piercings ou si vous êtes sur une chaise roulante pourvu que vous livriez les features à temps.
</p></blockquote>
<p>On présente rapidement l&#8217;entreprise de manière générale. Un lien vers une page plus détaillée peut être inséré. On note les exigences humaines. Si la ponctualité est importante, mettez le. Ces lignes sont la relation personnelle que vous voulez établir. C&#8217;est vous, et lui/elle. C&#8217;est aussi le moment de mettre les recrues à l&#8217;aise en faisant un contraste. Ici, c&#8217;est carte blanche. Si vous avez des valeurs, exposez les. Si vous avez des choses amusantes à dire, dites les. Si ce sont des phrases marketings dictées par le département com interne (&#8220;we value&#8230;&#8221;), faites-les sauter.</p>
<blockquote><p>
Profil technique :<br />
&#8211; Capable d&#8217;écrire en Python : un décorateur maison, un code téléchargeant des ressources en ligne avec gestion des erreurs, une interface en ligne de commande avec argparse.<br />
&#8211; sait créer et déployer un daemon sous Linux Fedora en prod via supervisor.<br />
&#8211; sait faire une branche et un merge git.<br />
Vous serez testé à l&#8217;entretien.<br />
Sur place vous travaillerez avec :<br />
&#8211; de la programmation asynchrone.<br />
&#8211; PosGres.<br />
&#8211; Le framework Scrapy.<br />
Ces notions ne seront pas testées, vous pourrez les apprendre sur le tas.</p>
</blockquote>
<p>Plutôt que d&#8217;utiliser des termes vagues comme &#8220;bon niveau&#8221;, &#8220;senior&#8221;, etc., donnez des moyens précis de mesurer un niveau. Notez qu&#8217;on ne parle pas de diplôme ici. Le meilleur prog que je connais a Bac -2.</p>
<p>On sépare l&#8217;indispensable du &#8220;est un plus&#8221;. Mais plutôt que de le tourner en exigence, on le liste comme quelque chose d&#8217;attractif.</p>
<blockquote><p>
Date de recrutement souhaitée : 3 mars<br />
Contrat : CDD dans un premier temps, possible recrutement en CDI.<br />
Rémunération : 30-40k<br />
Contact : wololo@lambdaboite.com ou 0123456789 (Linette Michalon, CTO et votre futur boss)<br />
Adresse : 69 avenue du coin de la rue 69777 La villette sur roustifailles (votre bureau vous y attend)<br />
Site Web : http://lambdaboite.com/travaillez-chez-nous
</p></blockquote>
<p>Nature du contrat, contact avec qui, quoi et où puis lien vers une carte.</p>
<p>On notifie que l&#8217;adresse est bien l&#8217;endroit où l&#8217;on va travailler et pas juste le centre administratif.</p>
<p>Un lien vers plus de détails sur les conditions de travail (temps pour se déplacer, transport, photos des bureaux, liens vers l&#8217;équipe, présentation des produits, etc) est bienvenu.</p>
<p>Et oui, rédiger une annonce prend du temps. Recruter correctement prend du temps.</p>
<h2>Copier / coller</h2>
<p>Comme je sais que les gens aiment bien les templates, voici la version intégrale, prête à être copiée.</p>
<p>Mais je déconseille de l&#8217;utiliser telle quelle. Tout comme un CV doit être réécrit pour chaque poste qu&#8217;on vise, une annonce doit l&#8217;être pour chaque poste qu&#8217;on veut pourvoir.</p>
<h3>Cherche Dev Backend Python</h3>
<p>Mon équipe de 3 dev a besoin d&#8217;un(e) pythonista pour travailler sur notre crawler de pages. La mission sera dans un premier temps de rajouter de nouvelles sources d&#8217;information à parser. Cela inclut une batterie de tests et de la documentation. D&#8217;autres tâches ponctuelles comme de la correction de bugs de notre ancien système et de la refactorisation des précédents crawlers sont à prévoir.</p>
<p>Nous : LambdaBoite est spécialisée dans la vente de LambdaProduit, notre but étant de satisfaire LambdaBesoin de LambdaTypeDeClient.</p>
<p>Vous : on se fiche de savoir si vous avez 23 ans, portez des piercings ou si vous êtes sur une chaise roulante pourvu que vous livriez les features à temps.</p>
<p>Profil technique :</p>
<p>&#8211; Capable d&#8217;écrire en Python : un décorateur maison, un code téléchargeant des ressources en ligne avec gestion des erreurs, une interface en ligne de commande avec argparse.<br />
&#8211; sait créer et déployer un daemon sous Linux Fedora en prod via supervisor.<br />
&#8211; sait faire une branche et un merge git.</p>
<p>Vous serez testé à l&#8217;entretien.</p>
<p>Sur place vous travaillerez avec :</p>
<p>&#8211; de la programmation asynchrone.<br />
&#8211; PosGres.<br />
&#8211; Le framework Scrapy.</p>
<p>Ces notions ne seront pas testées, vous pourrez les apprendre sur le tas.</p>
<p>&#8212;&#8212;&#8212;-</p>
<p>Contrat : CDD dans un premier temps, possible recrutement en CDI.<br />
Rémunération : 30-40k.<br />
Contact : wololo@lambdaboite.com ou 0123456789 (Linette Michalon, CTO et votre futur boss)<br />
Adresse : 69 avenue du coin de la rue 69777 La villette sur roustifailles (votre bureau vous y attend)<br />
Site Web : http://lambdaboite.com/travaillez-chez-nous</p>
<h2>Sortir du cadre</h2>
<p>Ce que je viens de faire là, c&#8217;est une annonce générique. La vérité c&#8217;est que je n&#8217;écrirais pas une annonce comme ça moi-même. Une fois que vous avez maîtrisé ce qui est important pour vous et la recrue, vous pouvez adapter le style pour en faire quelque chose de plus personnel, et souvent plus court. L&#8217;idéal est de faire transparaître l&#8217;état d&#8217;esprit de la boîte via l&#8217;annonce.</p>
<p>Bon évidemment si vous recrutez pour une énorme boîte dinosaure type EDF, vous êtes baisé. </p>
<p>Pour finir, n&#8217;oubliez pas que l&#8217;annonce n&#8217;est pas la manière à préférer pour recruter. Le bouche à oreille, les événements techniques (conf, rassemblements, etc.), les sites communautaires et même les restos / bars sont de bien meilleurs sources. Donc mettez une annonce en ligne, puis allez à la Pycon à Lyon la semaine prochaine ou allez boire un verre au Cardinal sur Richelieu à Paname. Ca marche mieux.</p>


feed_id: http://sametmax.com/?p=10490
title: Servir des fichiers statiques avec nginx
uri: Servir-des-fichiers-statiques-avec-nginx
url: http://sametmax.com/servir-des-fichiers-statiques-avec-nginx/
content:
<p>C&#8217;est un truc dont j&#8217;ai tout le temps besoin, alors l&#8217;article servira de pense bête. Marre de chercher à chaque fois :</p>
<pre>
        # sur django, on met tout dans /static/, donc par habitude je le fais
        # pour tout
        location /static/ {

            # Le dossier doit contenir le dossier 'static'. Par exemple si votre
            # arbo est /home/sametmax/repo/static, le chemin sera
            # /home/sametmax/repo. Rassurez-vous, personne n'aura accès aux
            # autres sous dossiers de "repo".
            root  /chemin/absolu/vers/dossier/;

            # On active la compression
            gzip  on;
            gzip_http_version 1.0;
            gzip_vary on;
            gzip_comp_level 6;
            gzip_proxied any;
            gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
            gzip_buffers 16 8k;

            # Sauf pour les vieux nav
            gzip_disable ~@~\MSIE [1-6].(?!.*SV1)~@~];

            # On dit au navigateur de le mettre en cache pour 3 mois. Faites gaffe,
            # mettez un param dans les url de vos balises script/link qui change
            # à chaque version du fichier, sinon vous ne pourrez pas mettre à jour
            # vos fichiers.
            expires modified +90d;
        }
</pre>


feed_id: http://sametmax.com/?p=12534
title: Rapatrier une branche d’un repo distant en local
uri: Rapatrier-une-branche-d-un-repo-distant-en-local
url: http://sametmax.com/rapatrier-une-branche-dun-repo-distant-en-local/
content:
<p>Vous avez un repo local et un remote. Une branche a été créée sur le remote, et vous voulez la récupérer en local :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">git checkout</span> <span style="color: #660033;">--track</span> nom_du_remote<span style="color: #000000; font-weight: bold;">/</span>nom_de_la_branche</pre></td></tr></table></div>

<p>Par exemple :</p>

<div class="wp_syntax"><table><tr><td class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">git checkout</span> <span style="color: #660033;">--track</span> origin<span style="color: #000000; font-weight: bold;">/</span>dev</pre></td></tr></table></div>

<p>Ce qui va avoir pour effet de créer une branche &#8220;dev&#8221; sur votre repo local, de vous switcher dessus, et la lier à la branche &#8220;dev&#8221; du remote &#8220;origin&#8221;.</p>
<p>Comme d&#8217;hab, assurez-vous que votre copie de travail est bien propre avant sinon ça va merder au moment de changer de branche.</p>
<p>Ouais, ouais, je sais, <code>checkout</code> est la commande fourre-tout de git qui fait absolument n&#8217;importe quoi. C&#8217;est relou. </p>


feed_id: http://sametmax.com/?p=12524
title: Rapport de l’INDMS : le niveau des développeurs
uri: Rapport-de-l-INDMS-le-niveau-des-développeurs
url: http://sametmax.com/rapport-de-lindms-le-niveau-des-developpeurs/
content:
<p>Dans un article précédent, j&#8217;avais souligné la baisse du niveau des devs et on m&#8217;avait demandé mes sources. Mes sources, comme souvent pour ce genre d&#8217;opinion, sont les études empiriques du très sérieux Institut National du Doigt Mouillé de Sam. Faudrait que je fasse un logo mais je suis une pine en graphique.</p>
<p>Aujourd&#8217;hui, à l&#8217;aide de chiffres scientifiquement approximatifs et d&#8217;analyse d&#8217;échantillons représentatifs localement, à moins que ce soit l&#8217;inverse, nous allons vous expliquer ce qui se trame.</p>
<p>Je ne suis pro en dev que depuis 10 ans. 10 ans, c&#8217;est court dans une carrière. Mais en informatique, c&#8217;est long. Suffisamment long pour avoir vu l&#8217;ère pré-<code>msql_real_escape</code>, les premiers ORM, la mode du NoSQL et le big Data. Suffisamment pour avoir vu le design via <code>table</code>, puis la psychose du xHTML valide strict et accessible pour finir sur le HTML 5 avec le retour du JS inline qui ne sert pas qu&#8217;à faire des flocons de neige. Suffisamment pour avoir vu Linux devenir utilisable, la programmation sur téléphone accessible (vous vous souvenez qu&#8217;avant on programmait les nokias en J2ME ?), la latence réseau devenir un bottleneck, le CPU et la mémoire étant relégués à un problème comptable sur 90% des projets. Et surtout, suffisamment pour voir le Dev Web passer d&#8217;un truc de bidouilleur à une spécialité à part entière du monde de l&#8217;informatique.</p>
<p>Mais même avant, sans faire de l&#8217;argent avec, j&#8217;avais les mains dedans. J&#8217;avais un ordi avec des disquettes 5 pouces, un écran en noir et vert et un bouton &#8220;turbo&#8221; qui overclockait le puce à 8Mhz. Wooosh ! Et encore avant, un ordinateur avec une cassette à bande magnétique que je n&#8217;ai jamais réussi à faire marcher.</p>
<p>Et puis on croise du monde, des gens d&#8217;expérience qui partagent. On lit des livres d&#8217;il y a 20 ans (<a href="http://www.wordplace.com/ap/index.shtml">almost perfect</a> est disponible gratos au fait). On travaille. On forme. On recrute.</p>
<p>Cela m&#8217;a amené a plusieurs constats.</p>
<h2>Le niveau de vie des développeurs s&#8217;est bien amélioré</h2>
<p>Que ce soit au niveau qualité de matériel (2 écran HD pour utiliser VI, c&#8217;est le luxe), accessibilité de l&#8217;information (Google, c&#8217;est plus facile qu&#8217;un magazine ou des man pages sur disquette), automatisation (on compile très rarement les dépendances tierces maintenant), facilité de trouver un job (y a des annonces partout), tout est plus confortable.</p>
<p>Mais ce n&#8217;est pas le plus important.</p>
<p>L&#8217;image des dev s&#8217;est améliorée. Être le geek au collège n&#8217;était pas vraiment une partie de plaisir. En fait si j&#8217;avais rencontré Max dans la cour de l&#8217;école, on se serait probablement mis sur la gueule.</p>
<p>Aujourd&#8217;hui on vend des magazines avec en couv&#8217; des geeks millionnaires, Hollywood s&#8217;est approprié la mythologie du hacker et la coolification (devrais-je dire coolifitude ?) de l&#8217;utilisation informatique rend la vie beaucoup plus facile.</p>
<p>Quand je dis à une meuf que je suis informaticien, elle ne fuit plus. C&#8217;est pratique. La logistique devenait compliquée.</p>
<div id="attachment_12525" style="width: 310px" class="wp-caption aligncenter"><a href="media/c68de6c3.histo.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/10/histo.png" class="grouped_elements" rel="tc-fancybox-group12524"><img src="media/b1abaa8f.histo-300x168.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/10/histo-300x168.png" alt="Utilisation du piège à loup en % de rencards." width="300" height="168" class="size-medium wp-image-12525" /></a><p class="wp-caption-text">La dernière fois que Max a choisi une carrière d&#8217;un soir, il était chirurgien esthétique.</p></div>
<h2>L&#8217;informatique a explosé</h2>
<p>Comme vous pouvez le voir sur ce graphique, le nombre de connards à utiliser l&#8217;informatique a drastiquement augmenté. Ce faisant, il y a donc beaucoup plus d&#8217;appareils nécessitant d&#8217;être programmés sur le marché, les rayons, le chaumières et les poubelles.</p>
<div id="attachment_12526" style="width: 310px" class="wp-caption aligncenter"><a href="media/b455c332.courbes.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/10/courbes.png" class="grouped_elements" rel="tc-fancybox-group12524"><img src="media/386a4385.courbes-300x168.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/10/courbes-300x168.png" alt="Progression de la situation situationelle" width="300" height="168" class="size-medium wp-image-12526" /></a><p class="wp-caption-text">C&#8217;est toujours mauvais quand on croise les effluves</p></div>
<p>Malgré des échelles qui n&#8217;ont rien à voir, la courbe de facilité des usages suit paresseusement celles des usagers, et ce n&#8217;est pas un hasard. La formule pour calculer la simplicité d&#8217;un système étant dépendante de la variable du nombre de boulets l&#8217;utilisant (Evidence = MasseConnards²).</p>
<p>Or, pour répondre à la fois à la simplification des usages, et à leur multiplication, il y a fallu créer un paquets d&#8217;abstractions qui ont rajouté des couches, ce qui explique la progression du niveau d&#8217;indirection.</p>
<h2>Les formations n&#8217;ont pas suivi</h2>
<p>Dans le cas le plus grave, elles ont des années de retard sur les technologies actuellement utilisées. Dans le meilleur des cas, elles sont dispensées par des gens qui ne travaillent pas, et donc ne fournissent pas aux apprenants les éléments nécessaires pour être un élément productif.</p>
<div id="attachment_12527" style="width: 310px" class="wp-caption aligncenter"><a href="media/f9b8556c.pie.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/10/pie.png" class="grouped_elements" rel="tc-fancybox-group12524"><img src="media/df7827c8.pie-300x168.png" data-original-source="http://sametmax.com/wp-content/uploads/2014/10/pie-300x168.png" alt="Enseignement uiversitaire en France" width="300" height="168" class="size-medium wp-image-12527" /></a><p class="wp-caption-text">Je voulais rajouter le pourcentage de profs qui avaient fait une migration de schéma en prod, mais LibreOffice n&#8217;accepte pas les chiffres négatifs.</p></div>
<p>Je voulais rajouter le pourcentage de profs qui avaient fait une migration de schéma en prod, mais LibreOffice n&#8217;accepte pas les chiffres négatifs.</p>
<p>Les bons informaticiens restent donc ceux qui se forment eux-mêmes. Via un projet personnel, par simple passion, en travaillant pour financer leurs études, etc. Même pendant la vie professionnelle, ceux qui ne deviennent pas obsolètes sont ceux qui continuent à apprendre. Car la formation en info, c&#8217;est toute sa vie. Et c&#8217;est un train où le paysage avance en même temps que soi, donc si on s&#8217;arrête, en vérité, on recule.</p>
<h2>Et du coup</h2>
<p>Le niveau des dev baisse. Pas de manière absolue, mais de manière relative au niveau dont le marché a besoin, et également en pourcentage de la population totale.</p>
<p>C&#8217;est lié à la conjoncture : plus de demande et plus de confort impliquent qu&#8217;il y a plus de monde qui se lance dedans. La démocratisation, c&#8217;est bien, mais ça apporte également un flot de personnes qui font ça comme job alimentaire. Or, si la formation ne suit pas, et qu&#8217;ils ne se forment pas, le nombre de technos continue d&#8217;augmenter. Les abstractions continuent de s&#8217;accumuler. Les nouveaux produits continuent de sortir.</p>
<p>Si bien que le besoin de dev augmente, mais également l&#8217;exigence de la somme des compétences requises progresse. Car si on a plus besoin de connaître la différence entre un little endian et un gros portoricain, pour dev une app Web moderne il faut maitriser : CSS, Javascript/Python/Ruby, HTML, quelques frameworks par dessus tout ça, une base de données et peut être un ORM, un système d&#8217;exploitation, potentiellement une machine virtuelle, un système de déploiement, des préprocesseurs, un système de files de tâches, un moteur de recherche, un système de cache&#8230;</p>
<p>Et l&#8217;attente des clients, comme des employeurs, sur le résultat, a elle aussi grandi. On veut du mieux, plus vite, plus ergonomique. Ils le font bien à côté. Par contre, ce qu&#8217;ils peuvent payer pour ça n&#8217;a pas beaucoup bougé en France, ils pensent toujours qu&#8217;avec un bon fichier de conf on peut faire faire un clone de Youtube pour pas cher.</p>
<p>Du coup les bons devs qui restent, ceux qui se sont formés et continuent de se former, ceux qui sont noyés dans la masse grandissante des spleenés de la programmation qu&#8217;on a attiré avec la promesse d&#8217;un job, ils se barrent. Ils se barrent là où on les paie à la hauteur de leur compétence : aux USA et aux UK.</p>
<p>Je résume :</p>
<ul>
<li>La demande en dev est en hausse.</li>
<li>A corréler avec l&#8217;augmentation du nombre d&#8217;abstractions.</li>
<li>Il y a plus de dev avec des boulots alimentaires.</li>
<li>Les meilleurs devs se cassent ou se mettent à leur compte.</li>
</ul>
<p>A l&#8217;embauche, le nombre de bons dev disponibles comparé à la demande grandissante et au nombre total de candidats, est en chute libre. Et ce, malgré le nombre de devs de talent, absolu, qui lui augmente dans le monde par le simple truchement de la démographie et de l&#8217;émulsion technologique.</p>
<p>Dans la vraie vie vivante, ça se traduit par des entretiens déprimants, des embauches tristes et des cours d&#8217;info frustrants.</p>
<p>Et la situation ne va pas s&#8217;arranger. Les besoins vont continuer à croître. Les bons dev ne vont pas sortir du chapeau. Faites en sorte que ce soit une bonne nouvelle pour vous :</p>
<ul>
<li>Si vous êtes dev, vous avez l&#8217;occasion de sortir du lot.</li>
<li>Si vous êtes recruteur, visez juste, et vous aurez un avantage concurrentiel non négligeable.</li>
</ul>
<p>Comment faire ? Arf, ça pourrait être un autre article. Un jour :)</p>


