# articles

feed_id: http://sametmax.com/?p=5568
title: La galère pour configurer un email chez Opéra!
uri: La-galère-pour-configurer-un-email-chez-Opéra
url: http://sametmax.com/la-galere-pour-configurer-un-email-chez-opera/
content:
<p>La page d&#8217;intro semblait avenante, se disait simple, mais non, Opéra fait du grand n&#8217;importe quoi à l&#8217;instar des autres service de mail. Plus c&#8217;est compliqué, plus ça leur plait&#8230;</p>
<p>En me levant ce matin, plutôt de bonne hummeur je me suis dit que j&#8217;allais tester Opéra Mail, d&#8217;autant que sam avait fait un <a href="http://sametmax.com/quitter-google-recherche-email-et-chat/" title="Quitter Google : recherche, email et chat">article dessus</a>.</p>
<p>Bon d&#8217;accord j&#8217;y go!</p>
<p>(Attention SVP placez-vous dans l&#8217;esprit de quelqu&#8217;un qui n&#8217;a pas envie de chercher, 99% des utilisateurs internet, je veux un e-mail, pas me marrier)</p>
<p><strong>Premiere page déjà ça coince!</strong><br />
<a href="https://mail.opera.com/">https://mail.opera.com/</a></p>
<p>Je clique où? je fais quoi? Il m&#8217;a fallut 10 secondes et du hasard pour percuter qu&#8217;il fallait cliquer sur le bouton bleu sans entrer quoique ce soit dans le champs e-mail à côté.<br />
Ben oui si y a un champs c&#8217;est qu&#8217;il faut le remplir! si je clique sans remplir il va y avoir une erreur je vais perdre ma page, etc, <a href="http://sametmax.com/il-ne-faut-pas-prendre-des-gens-pour-des-cons-mais-ne-jamais-oublier-quils-en-sont/" title="Il ne faut pas prendre des gens pour des cons mais ne jamais oublier qu’ils en sont">souvenez-vous</a>).</p>
<p>Bon passons, j&#8217;arrive sur la page où je dois rentrer&#8230;.un e-mail&#8230; Je suis fatigué&#8230;<br />
Je viens pour avoir un e-mail il faut que je donne mon e-mail, ça continue&#8230;.</p>
<p>Admettons&#8230;</p>
<p>Je m&#8217;enregistre et là je reçois un email de bienvenue, bla bla&#8230; C&#8217;est cool sauf que voilà cet email est un email de confirmation avec pas moins de &#8230; 7 liens !<br />
Comme un bourrin je clique sur le premiere lien &#8220;before getting started activate your account&#8221;&#8230;</p>
<p>J&#8217;arrive sur une page internet avec mon compte opéra activé, c&#8217;est beau ! Comme en 1996 au début du net, les fonts, les icônes, les coueleurs, tout est là pour rappeler le bon vieux temps du 8 bits&#8230;</p>
<p>Bon je m&#8217;en fiche un peu car en fait je veux pas de leur portail, je veux juste un email.<br />
Ha au fait je vous l&#8217;ai dit ? Vous êtes automatiquement ajouté à leur réseaux social, forum, blog, etc&#8230;</p>
<p>Bon je cherche les infos pour mon email, et&#8230; Y en a PAS!<br />
Il y en a JUSTE PAS !<br />
Dans votre compte opéra ne cherchez pas d&#8217;infos sur votre email il n&#8217;y en a pas !<br />
Il faut retourner dans l&#8217;email de confirmation, et cliquer sur un des 7 (nains) liens celui-là : https://mail.opera.com/mail/<br />
Et ouiii il fallait suivre voyons !</p>
<p>donc j&#8217;arrive enfin sur ma boite email (la vrai) et j&#8217;ai un joli message qui m&#8217;attends:</p>
<blockquote><p>
à  pol_pot1925</p>
<p>Bonjour !</p>
<p>Bienvenue à My Opera Mail. Nous vous offrons un accès sécurisé, efficace et facile à utiliser à vos emails sur presque n&#8217;importe quel type d&#8217;appareil. Que vous naviguiez sur un PC ou sur un téléphone avec Opera Mini, allez à https://mail.opera.com/. Vous pouvez aussi connecter vos autres comptes emails pour lire tout votre courrier à un seul endroit. Il suffit d&#8217;entrer vos adresses et mots de passe dans les réglages du compte, et nous nous occuperons du reste.</p>
<p>Si vous préférez utiliser un client email dédie, comme celui intégré à Opera, vous pouvez vous connecter à votre compte en utilisant ces réglages :</p>
<p>Serveur IMAP : imap.myopera.com port 993 (SSL uniquement)<br />
Serveur SMTP : smtp.myopera.com port 465 (SSL uniquement) ou 587 (STARTTLS uniquement)
</p></blockquote>
<p>Ouf voilà les infos pour configurer mon client e-mail. Je rentre tout ça et ça marche pas, en fait j&#8217;avais mis mon user mais sans l&#8217;adresse, je vous rappelle qu&#8217;à AUCUN MOMENT OPERA NE VOUS DONNE VOTRE ADRESSE EMAIL.<br />
Il faut la deviner ! C&#8217;est le jeu ma pauvre lucette. Heureusement on peu l&#8217;aperçevoir timidement en haut à droite de vote interface web mail.opera.com.</p>
<p>En gros j&#8217;ai passé 30 minutes à créer un email et configurer ce dernier dans mon client mail. Sous Gmail c&#8217;est tout aussi chiant je vous rassure mais avec le temps je connais le chemin.</p>
<p>Bref c&#8217;est pas demain la veille qu&#8217;on aura des trucs simples à configurer pour communiquer&#8230;</p>
<p>PS: je vous ai épargné la config des serveurs sur le client mail avec smpt ou imap à choisir, qui dans le mode des humains normaux connait la différence ? On ne devrait même pas avoir à configurer ça&#8230;</p>
<p>C&#8217;était mon coup de geule du lundi, à vous Cognac Jay</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=5568&amp;md5=1d88afb79e345ae1ca130f707c7237f1" 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=5574
title: [FFMPEG] – Encoder un répertoire entier en mp3
uri: FFMPEG-Encoder-un-répertoire-entier-en-mp3
url: http://sametmax.com/ffmpeg-encoder-un-repertoire-entier-en-mp3/
content:
<p>Petite commande fort sympatoche pour encoder tout un répertoire avec ffmpeg en ligne de commande.</p>
<p>(Il faut avoir ffmpeg d&#8217;installé: <a href="http://sametmax.com/installer-ffmpeg-avec-x264-et-support-mp3/" title="installer ffmpeg avec x264 et support mp3">voir ici pour le compiler</a> ou plus bas)<br />
<strong>sous Ubuntu (avec un max de codecs):</strong></p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #c20cb9; font-weight: bold;">apt-get</span> <span style="color: #c20cb9; font-weight: bold;">install</span> libavcodec-unstripped-<span style="color: #000000;">52</span> libavdevice-unstripped-<span style="color: #000000;">52</span> libavformat-unstripped-<span style="color: #000000;">52</span> libavutil-unstripped-<span style="color: #000000;">50</span> libpostproc-unstripped-<span style="color: #000000;">51</span> libswscale-unstripped-<span style="color: #000000;">0</span> <span style="color: #c20cb9; font-weight: bold;">ffmpeg</span></pre></div></div>

<p>Ouvrez un shell dans le répertoire où se trouve les fichiers  (videos, mp4, wav, etc) à convertirs en mp3 tapez:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">for</span> <span style="color: #c20cb9; font-weight: bold;">file</span> <span style="color: #000000; font-weight: bold;">in</span> <span style="color: #000000; font-weight: bold;">*</span>.<span style="color: #000000; font-weight: bold;">*</span>; <span style="color: #000000; font-weight: bold;">do</span> <span style="color: #000000; font-weight: bold;">`</span><span style="color: #c20cb9; font-weight: bold;">ffmpeg</span> <span style="color: #660033;">-i</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$file</span>&quot;</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$file</span>.mp3&quot;</span><span style="color: #000000; font-weight: bold;">`</span>;<span style="color: #000000; font-weight: bold;">done</span></pre></div></div>

<p>Ffmpeg va automatiquement encoder en mp3 44khz stéréo vos fichiers en un tour de main. Vous pouvez rajouter des options de bitrate (ie: -b 192k) ou utilisez le filtre pour convertir qu&#8217;un certain type de fichier en remplacant *.* par *.avi , *.mp4, etc.</p>
<p>Ps: N&#8217;hésitez pas à partager vos lignes de commandes utiles, je les rajouterai si besoin (encodage audio / video)</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=5574&amp;md5=cd183de6fece9d7eaabb595dd99c792d" 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=5588
title: Le problème de Monty Hall illustré en Python
uri: Le-problème-de-Monty-Hall-illustré-en-Python
url: http://sametmax.com/le-probleme-de-monty-hall-illustre-en-python/
content:
<p>En plus d&#8217;être un article qui va nous faire remonter dans toutes les recherches sur les Monty Python, il va ravir nos amis statisticiens.</p>
<p>Le <a href="https://fr.wikipedia.org/wiki/Probl%C3%A8me_de_Monty_Hall">problème de Monty Hall</a> est un problème mathématique si simple qu&#8217;un enfant de 5 ans peut le comprendre. Et sa véritable réponse est tellement contre intuitive que des centaines de doctorants ont longtemps contesté sa véracité.</p>
<p>Il part d&#8217;un jeu télévisé américain présenté par le canadien <a href="https://fr.wikipedia.org/wiki/Monty_Hall">Monte Halperin</a>, plus connu sous son nom de scène, Monty Hall. À un moment du jeu le candidat se retrouve face à 3 portes, derrière deux d&#8217;entre elles se cache une chèvre. Derrière l&#8217;une se cache une voiture à gagner.</p>
<p>Maintenant voilà l&#8217;astuce :</p>
<p>Quand le candidat choisit une porte, le présentateur, <strong>qui sait ce qu&#8217;il y a derrière les portes</strong>, ouvre une des portes qui n&#8217;a pas été choisie. Il s&#8217;arrange pour que la porte ouverte montre toujours une chèvre. Il demande alors si le candidat veut garder sa porte ou prendre la troisième porte.</p>
<p>Question : </p>
<p><em>Le candidat doit-il changer de porte ?</em></p>
<h2>Là où le cerveau vous lache</h2>
<p>Les êtres humains normaux, comme vous, moi et Jean Dujardin, ont tendance à sortir une réponse qui ressemble à peu prêt à ça : &#8220;on s&#8217;en branle connard, il a une chance sur deux, c&#8217;est pareil qu&#8217;il reste ou qu&#8217;il change&#8221;.</p>
<p>Sauf que non.</p>
<p><a href="https://fr.wikipedia.org/wiki/Marilyn_vos_Savant">Marilyn vos Savant</a> (un nom pareil putain, c&#8217;est prédestiné), a qui on avait posé la question, a une version un peu différente. Or la miss est notamment célèbre parce qu&#8217;elle a figuré dans le Guinness des records pour son QI de 190.</p>
<p>Selon elle, il vaut mieux changer de portes, car on a dans ce cas 2 chances sur 3 de gagner, et non une sur deux.</p>
<p>Si ça vous la coupe, ne vous inquiétez pas, elle a reçu des milliers de lettres plus ou moins sympathiques de scientifiques du monde entier pour la traiter de sale connasse qui ne comprend rien aux stats (je paraphrase). Notre cerveau n&#8217;aime pas trop cette réponse.</p>
<p>Si vous vous sentez bien réveillé, vous pouvez lire une des <a href="https://en.wikipedia.org/wiki/Monty_Hall_Problem">dizaines d&#8217;explications du phénomène</a>. Peut être qu&#8217;il y en a une qui fera tilt. Sinon, faites comme moi, codez un petit script.</p>
<h2>Avec Python, on se sent moins con</h2>
<p>Rappelez-vous les règles :</p>
<ol>
<li>3 portes, 2 chèvres, une voiture.</li>
<li>Le participant choisit une porte au hasard, mais ne l&#8217;ouvre pas.</li>
<li>Le présentateur, qui sait où est la voiture, fait monter la sauce en ouvrant une des deux portes restantes, dévoilant toujours une chèvre.</li>
<li>Le participant se voit alors offrir le choix de garder sa porte ou en changer.</li>
</ol>
<p>Et ça donne ça, dans la langue de Guido Van Rossum :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># -*- coding: utf-8 -*-</span>
&nbsp;
&nbsp;
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">random</span>
&nbsp;
&nbsp;
victoires_quand_on_change = victoires_quand_on_reste = <span style="color: #ff4500;">0</span>
portes = <span style="color: black;">&#40;</span>u<span style="color: #483d8b;">&quot;Voiture&quot;</span>, u<span style="color: #483d8b;">&quot;Chèvre&quot;</span>, u<span style="color: #483d8b;">&quot;Chèvre&quot;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># On fait 10000 parties du jeu</span>
<span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">xrange</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">10000</span><span style="color: black;">&#41;</span>:
&nbsp;
    <span style="color: #808080; font-style: italic;"># Le joueur prend une porte au hasard</span>
    porte_choisie = portes<span style="color: black;">&#91;</span><span style="color: #dc143c;">random</span>.<span style="color: black;">randint</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span>, <span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Le présentateur ouvre une des deux autres porte et c'est toujours une </span>
    <span style="color: #808080; font-style: italic;"># chèvre derrière celle-ci. La dernière porte contient donc une</span>
    <span style="color: #808080; font-style: italic;"># voiture si le candidat a choisit une chèvre, et inversement.</span>
    porte_restante = u<span style="color: #483d8b;">'Chèvre'</span> <span style="color: #ff7700;font-weight:bold;">if</span> porte_choisie == u<span style="color: #483d8b;">&quot;Voiture&quot;</span> <span style="color: #ff7700;font-weight:bold;">else</span> u<span style="color: #483d8b;">&quot;Voiture&quot;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># int(False) == 0 et int(True) == 1 en Python</span>
    victoires_quand_on_change += <span style="color: #008000;">int</span><span style="color: black;">&#40;</span>porte_restante == u<span style="color: #483d8b;">'Voiture'</span><span style="color: black;">&#41;</span>
    victoires_quand_on_reste += <span style="color: #008000;">int</span><span style="color: black;">&#40;</span>porte_choisie == u<span style="color: #483d8b;">'Voiture'</span><span style="color: black;">&#41;</span>
&nbsp;
&nbsp;
<span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>u<span style="color: #483d8b;">&quot;Victoires quand on reste : {}&quot;</span>.<span style="color: black;">format</span><span style="color: black;">&#40;</span>victoires_quand_on_reste<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>u<span style="color: #483d8b;">&quot;Victoires en change : {}&quot;</span>.<span style="color: black;">format</span><span style="color: black;">&#40;</span>victoires_quand_on_change<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #808080; font-style: italic;">## Victoires quand on reste : 3354</span>
<span style="color: #808080; font-style: italic;">## Victoires en change : 6646</span></pre></div></div>

<p>On peut lancer le script autant de fois qu&#8217;on veut, on retrouve toujours cette proportion de 2 / 3 de victoires si on change, et 1 / 3 si on reste. Perturbant, mais au moins je sais que je n&#8217;ai pas 190 de QI.</p>
<hr />
<p><a href="https://github.com/sametmax/codes-des-articles/blob/master/2013/avril/monty_hall.py">Télécharger le code de l&#8217;article.</a></p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=5588&amp;md5=dbae07595b28b275bdd16fbfbf0d4466" 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=5600
title: Goto en Python
uri: Goto-en-Python
url: http://sametmax.com/goto-en-python/
content:
<p>La bonne vieille époque du BASIC vous manque ? Vous voulez retrouver le pouvoir d&#8217;aller et venir n&#8217;importe où dans votre code et faire des scripts spaghetti bien dégueulasses ?</p>
<p><a href="http://entrian.com/goto/download.html">Téléchargez Go To pour Python</a>.</p>
<p>Le 1 avril est bien passé, et cette lib existe pour de vrai. Elle vous permet de retomber en enfance où on dirait que toi tu peux poser un label et moi je peux y aller directement :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">from</span> goto <span style="color: #ff7700;font-weight:bold;">import</span> goto, label
&nbsp;
label .<span style="color: black;">start</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">&quot;C'est pas du jeu&quot;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">4</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">print</span> i
    <span style="color: #ff7700;font-weight:bold;">if</span> i == <span style="color: #ff4500;">2</span>:
        <span style="color: #ff7700;font-weight:bold;">try</span>:
            output = message
        <span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">NameError</span>:
            <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">&quot;T'as oublié le message.&quot;</span>
            message = <span style="color: #483d8b;">&quot;Salut&quot;</span>
            goto .<span style="color: black;">start</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">print</span> output, <span style="color: #483d8b;">&quot;<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span></pre></div></div>

<p>Si vous regardez le code souce, vous verrez que l&#8217;implémentation est une bouillie immonde qui sauvegarde les frames dans un cache et les rebalancent quand on gotouse.</p>
<p>Merci à l&#8217;auteur d&#8217;avoir pondu cette lib indispensable, si elle n&#8217;avait pas existé, je l&#8217;aurais codé.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=5600&amp;md5=8fad2a0a7cfa7c8732dd0f63ba159701" 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=4381
title: Obfuscating Python
uri: Obfuscating-Python
url: http://sametmax.com/obfuscating-python/
content:
<p>Python est un langage qu&#8217;il est difficile de rendre illisible. Difficile, mais pas impossible.</p>
<p>D&#8217;abord, les techniques habituelles de substitutions de lettres par leurs codes ASCII sont toujours valables. Le fameux easter egg <code>import this</code> en fait d&#8217;ailleurs usage;  si vous ouvrez le fichier dont le chemin est contenu dans <code>this.__file__</code>, vous trouverez :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">s = <span style="color: #483d8b;">&quot;&quot;&quot;Gur Mra bs Clguba, ol Gvz Crgref
&nbsp;
Ornhgvshy vf orggre guna htyl.
Rkcyvpvg vf orggre guna vzcyvpvg.
Fvzcyr vf orggre guna pbzcyrk.
Pbzcyrk vf orggre guna pbzcyvpngrq.
Syng vf orggre guna arfgrq.
Fcnefr vf orggre guna qrafr.
Ernqnovyvgl pbhagf.
Fcrpvny pnfrf nera'g fcrpvny rabhtu gb oernx gur ehyrf.
Nygubhtu cenpgvpnyvgl orngf chevgl.
Reebef fubhyq arire cnff fvyragyl.
Hayrff rkcyvpvgyl fvyraprq.
Va gur snpr bs nzovthvgl, ershfr gur grzcgngvba gb thrff.
Gurer fubhyq or bar-- naq cersrenoyl bayl bar --boivbhf jnl gb qb vg.
Nygubhtu gung jnl znl abg or boivbhf ng svefg hayrff lbh'er Qhgpu.
Abj vf orggre guna arire.
Nygubhtu arire vf bsgra orggre guna *evtug* abj.
Vs gur vzcyrzragngvba vf uneq gb rkcynva, vg'f n onq vqrn.
Vs gur vzcyrzragngvba vf rnfl gb rkcynva, vg znl or n tbbq vqrn.
Anzrfcnprf ner bar ubaxvat terng vqrn -- yrg'f qb zber bs gubfr!&quot;&quot;&quot;</span>
&nbsp;
d = <span style="color: black;">&#123;</span><span style="color: black;">&#125;</span>
<span style="color: #ff7700;font-weight:bold;">for</span> c <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: black;">&#40;</span><span style="color: #ff4500;">65</span>, <span style="color: #ff4500;">97</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">26</span><span style="color: black;">&#41;</span>:
        d<span style="color: black;">&#91;</span><span style="color: #008000;">chr</span><span style="color: black;">&#40;</span>i+c<span style="color: black;">&#41;</span><span style="color: black;">&#93;</span> = <span style="color: #008000;">chr</span><span style="color: black;">&#40;</span><span style="color: black;">&#40;</span>i+<span style="color: #ff4500;">13</span><span style="color: black;">&#41;</span> <span style="color: #66cc66;">%</span> <span style="color: #ff4500;">26</span> + c<span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">&quot;&quot;</span>.<span style="color: black;">join</span><span style="color: black;">&#40;</span><span style="color: black;">&#91;</span>d.<span style="color: black;">get</span><span style="color: black;">&#40;</span>c, c<span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">for</span> c <span style="color: #ff7700;font-weight:bold;">in</span> s<span style="color: black;">&#93;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Ensuite, il y a le fait qu&#8217;il est possible de spécifier (en Python 2.7, mais plus Python 3), l&#8217;encoding du module en ROT13, base64 ou même zip. Au lieux de mettre <code> # -*- coding: utf8 -*-</code>, vous pouvez faire :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># -*- coding: rot13 -*-</span>
&nbsp;
cevag h<span style="color: #483d8b;">'Fnz rg Znk, cnepr dhr obver frhy rfg zbvaf qebyr dhr pbqre n cyhfvrhef'</span></pre></div></div>

<p>Mais au dela de ces petites astuces, il y a bien entendu la véritable offuscation, celle qui utilise des imbrications d&#8217;instructions capilotractées avec de multiples niveaux de nesting dans des onliners qui s&#8217;étendent sur des kilomètres en incluant des noms de variables alambiqués le tout organisé dans des structures syntaxiques volontairement obscures en détournant des capacités du langage pour en faire une indigeste bouillie immonde dont la lecture provoquera des saignement durant la phrase de vomi. Comme cette phrase.</p>
<p>Généralement ça passe par un usage massif des features que Guido déteste comme les lambdas ou les <code>;</code>.</p>
<p>Il y a <a href="http://docs.python.org/2/faq/programming.html#is-it-possible-to-write-obfuscated-one-liners-in-python">les classiques</a> onliners à base de map / reduce, par exemples les 1000 premiers nombres &#8230; premiers :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #008000;">filter</span><span style="color: black;">&#40;</span><span style="color: #008000;">None</span>,<span style="color: #008000;">map</span><span style="color: black;">&#40;</span><span style="color: #ff7700;font-weight:bold;">lambda</span> y:y<span style="color: #66cc66;">*</span><span style="color: #008000;">reduce</span><span style="color: black;">&#40;</span><span style="color: #ff7700;font-weight:bold;">lambda</span> x,y:x<span style="color: #66cc66;">*</span>y<span style="color: #66cc66;">!</span>=<span style="color: #ff4500;">0</span>, <span style="color: #008000;">map</span><span style="color: black;">&#40;</span><span style="color: #ff7700;font-weight:bold;">lambda</span> x,y=y:y<span style="color: #66cc66;">%</span>x,<span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">2</span>,<span style="color: #008000;">int</span><span style="color: black;">&#40;</span><span style="color: #008000;">pow</span><span style="color: black;">&#40;</span>y,<span style="color: #ff4500;">0.5</span><span style="color: black;">&#41;</span>+<span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>,<span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>,<span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">2</span>,<span style="color: #ff4500;">1000</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Ensuite il y a ceux qui aiment se la jouer &#8220;mes variables ont des noms de code Fortran&#8221; :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: black;">&#40;</span><span style="color: #ff7700;font-weight:bold;">lambda</span> Ru,Ro,Iu,Io,IM,Sx,Sy:<span style="color: #008000;">reduce</span><span style="color: black;">&#40;</span><span style="color: #ff7700;font-weight:bold;">lambda</span> x,y:x+y,<span style="color: #008000;">map</span><span style="color: black;">&#40;</span><span style="color: #ff7700;font-weight:bold;">lambda</span> y,
Iu=Iu,Io=Io,Ru=Ru,Ro=Ro,Sy=Sy,L=<span style="color: #ff7700;font-weight:bold;">lambda</span> yc,Iu=Iu,Io=Io,Ru=Ru,Ro=Ro,i=IM,
Sx=Sx,Sy=Sy:<span style="color: #008000;">reduce</span><span style="color: black;">&#40;</span><span style="color: #ff7700;font-weight:bold;">lambda</span> x,y:x+y,<span style="color: #008000;">map</span><span style="color: black;">&#40;</span><span style="color: #ff7700;font-weight:bold;">lambda</span> x,xc=Ru,yc=yc,Ru=Ru,Ro=Ro,
i=i,Sx=Sx,F=<span style="color: #ff7700;font-weight:bold;">lambda</span> xc,yc,x,y,k,f=<span style="color: #ff7700;font-weight:bold;">lambda</span> xc,yc,x,y,k,f:<span style="color: black;">&#40;</span>k<span style="color: #66cc66;">&lt;</span>=<span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span><span style="color: #ff7700;font-weight:bold;">or</span> <span style="color: black;">&#40;</span>x<span style="color: #66cc66;">*</span>x+y<span style="color: #66cc66;">*</span>y
<span style="color: #66cc66;">&gt;</span>=<span style="color: #ff4500;">4.0</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">or</span> <span style="color: #ff4500;">1</span>+f<span style="color: black;">&#40;</span>xc,yc,x<span style="color: #66cc66;">*</span>x-y<span style="color: #66cc66;">*</span>y+xc,<span style="color: #ff4500;">2.0</span><span style="color: #66cc66;">*</span>x<span style="color: #66cc66;">*</span>y+yc,k-<span style="color: #ff4500;">1</span>,f<span style="color: black;">&#41;</span>:f<span style="color: black;">&#40;</span>xc,yc,x,y,k,f<span style="color: black;">&#41;</span>:<span style="color: #008000;">chr</span><span style="color: black;">&#40;</span>
<span style="color: #ff4500;">64</span>+F<span style="color: black;">&#40;</span>Ru+x<span style="color: #66cc66;">*</span><span style="color: black;">&#40;</span>Ro-Ru<span style="color: black;">&#41;</span>/Sx,yc,<span style="color: #ff4500;">0</span>,<span style="color: #ff4500;">0</span>,i<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>,<span style="color: #008000;">range</span><span style="color: black;">&#40;</span>Sx<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>:L<span style="color: black;">&#40;</span>Iu+y<span style="color: #66cc66;">*</span><span style="color: black;">&#40;</span>Io-Iu<span style="color: black;">&#41;</span>/Sy<span style="color: black;">&#41;</span>,<span style="color: #008000;">range</span><span style="color: black;">&#40;</span>Sy
<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#40;</span>-<span style="color: #ff4500;">2.1</span>, <span style="color: #ff4500;">0.7</span>, -<span style="color: #ff4500;">1.2</span>, <span style="color: #ff4500;">1.2</span>, <span style="color: #ff4500;">30</span>, <span style="color: #ff4500;">80</span>, <span style="color: #ff4500;">24</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Ce qui va afficher cette belle composition de Mandelbrot (si votre terminal fait 80 colonnes de large) :</p>
<div id="attachment_5606" class="wp-caption aligncenter" style="width: 529px"><a href="media/8a8da48d.Espace-de-travail-1_004.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2013/04/Espace-de-travail-1_004.jpg"><img class=" wp-image-5606 " title="La génération procédurale : ou comment faire de Zolies choZes avec 1ko de code." src="media/8a8da48d.Espace-de-travail-1_004.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2013/04/Espace-de-travail-1_004.jpg" alt="Mandelbrot dans un terminal" width="519" height="337" /></a><p class="wp-caption-text">La génération procédurale : ou comment faire de Zolies choZes avec 1ko de code.</p></div>
<p>D&#8217;ailleurs, pour l&#8217;offuscation, on adore les trucs de maths parce que ça donne l&#8217;air intelligent et compliqué, et Mandelbrot est un truc très prisé puisqu&#8217;avec peu de lignes on peut outputer du Dali Période Guimauve automatiquement :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">_                                      =   <span style="color: black;">&#40;</span>
                                        <span style="color: #ff4500;">255</span>,
                                      <span style="color: #ff7700;font-weight:bold;">lambda</span>
                               V       ,B,c
                             :c   <span style="color: #ff7700;font-weight:bold;">and</span> Y<span style="color: black;">&#40;</span>V<span style="color: #66cc66;">*</span>V+B,B,  c
                               -<span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span><span style="color: #ff7700;font-weight:bold;">if</span><span style="color: black;">&#40;</span><span style="color: #008000;">abs</span><span style="color: black;">&#40;</span>V<span style="color: black;">&#41;</span><span style="color: #66cc66;">&lt;</span><span style="color: #ff4500;">6</span><span style="color: black;">&#41;</span><span style="color: #ff7700;font-weight:bold;">else</span>
               <span style="color: black;">&#40;</span>              <span style="color: #ff4500;">2</span>+c-<span style="color: #ff4500;">4</span><span style="color: #66cc66;">*</span><span style="color: #008000;">abs</span><span style="color: black;">&#40;</span>V<span style="color: black;">&#41;</span><span style="color: #66cc66;">**</span>-<span style="color: #ff4500;">0.4</span><span style="color: black;">&#41;</span>/i
                 <span style="color: black;">&#41;</span>  <span style="color: #66cc66;">;</span>v,      x=<span style="color: #ff4500;">1500</span>,<span style="color: #ff4500;">1000</span><span style="color: #66cc66;">;</span>C=<span style="color: #008000;">range</span><span style="color: black;">&#40;</span>v<span style="color: #66cc66;">*</span>x
                  <span style="color: black;">&#41;</span><span style="color: #66cc66;">;</span>import  <span style="color: #dc143c;">struct</span><span style="color: #66cc66;">;</span>P=<span style="color: #dc143c;">struct</span>.<span style="color: black;">pack</span><span style="color: #66cc66;">;</span>M,\
            j  =<span style="color: #483d8b;">'&lt;QIIHHHH'</span>,<span style="color: #008000;">open</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'M.bmp'</span>,<span style="color: #483d8b;">'wb'</span><span style="color: black;">&#41;</span>.<span style="color: black;">write</span>
<span style="color: #ff7700;font-weight:bold;">for</span> X <span style="color: #ff7700;font-weight:bold;">in</span> j<span style="color: black;">&#40;</span><span style="color: #483d8b;">'BM'</span>+P<span style="color: black;">&#40;</span>M,v<span style="color: #66cc66;">*</span>x<span style="color: #66cc66;">*</span><span style="color: #ff4500;">3</span>+<span style="color: #ff4500;">26</span>,<span style="color: #ff4500;">26</span>,<span style="color: #ff4500;">12</span>,v,x,<span style="color: #ff4500;">1</span>,<span style="color: #ff4500;">24</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: #ff7700;font-weight:bold;">or</span> C:
            i  ,Y=_<span style="color: #66cc66;">;</span>j<span style="color: black;">&#40;</span>P<span style="color: black;">&#40;</span><span style="color: #483d8b;">'BBB'</span>,<span style="color: #66cc66;">*</span><span style="color: black;">&#40;</span><span style="color: #ff7700;font-weight:bold;">lambda</span> T:<span style="color: black;">&#40;</span>T<span style="color: #66cc66;">*</span><span style="color: #ff4500;">80</span>+T<span style="color: #66cc66;">**</span><span style="color: #ff4500;">9</span>
                  <span style="color: #66cc66;">*</span>i-<span style="color: #ff4500;">950</span><span style="color: #66cc66;">*</span>T  <span style="color: #66cc66;">**</span><span style="color: #ff4500;">99</span>,T<span style="color: #66cc66;">*</span><span style="color: #ff4500;">70</span>-<span style="color: #ff4500;">880</span><span style="color: #66cc66;">*</span>T<span style="color: #66cc66;">**</span><span style="color: #ff4500;">18</span>+<span style="color: #ff4500;">701</span><span style="color: #66cc66;">*</span>
                 T  <span style="color: #66cc66;">**</span><span style="color: #ff4500;">9</span>     ,T<span style="color: #66cc66;">*</span>i<span style="color: #66cc66;">**</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>-T<span style="color: #66cc66;">**</span><span style="color: #ff4500;">45</span><span style="color: #66cc66;">*</span><span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#40;</span><span style="color: #008000;">sum</span><span style="color: black;">&#40;</span>
               <span style="color: black;">&#91;</span>              Y<span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span>,<span style="color: black;">&#40;</span>A<span style="color: #66cc66;">%</span>3/<span style="color: #ff4500;">3</span>.+X<span style="color: #66cc66;">%</span>v+<span style="color: black;">&#40;</span>X/v+
                               A/<span style="color: #ff4500;">3</span>/<span style="color: #ff4500;">3</span>.-x/<span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span>/1j<span style="color: black;">&#41;</span><span style="color: #66cc66;">*</span><span style="color: #ff4500;">2.5</span>
                             /x   -<span style="color: #ff4500;">2.7</span>,i<span style="color: black;">&#41;</span><span style="color: #66cc66;">**</span><span style="color: #ff4500;">2</span> <span style="color: #ff7700;font-weight:bold;">for</span>  \
                               A       <span style="color: #ff7700;font-weight:bold;">in</span> C
                                      <span style="color: black;">&#91;</span>:<span style="color: #ff4500;">9</span><span style="color: black;">&#93;</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
                                        /<span style="color: #ff4500;">9</span><span style="color: black;">&#41;</span>
                                       <span style="color: black;">&#41;</span>   <span style="color: black;">&#41;</span></pre></div></div>

<p>Notez cette fois que le code, en plus d&#8217;être particulièrement imbuvable, a été gentiment indenté pour ressembler à la figure qu&#8217;il va lui même pondre dans le fichier <em>M.bmp</em> que voici :</p>
<p><a href="http://sametmax.com/wp-content/uploads/2013/04/mandelbrot.bmp"><img src="http://sametmax.com/wp-content/uploads/2013/04/mandelbrot.bmp" alt="" title="En plus un set de Mandelbrot, c&#039;est indépendant de la résolution. On peut en pondre de taille arbitraire. C&#039;est trop cool, comme de l&#039;argent infini mais pour des images qui servent à rien." class="aligncenter size-full wp-image-5607" /></a></p>
<p>Mais bien entendu il y a des gens qui arrivent à faire des trucs moches sans entrainement. Par exemple des codeurs JS qui vous font ça:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #483d8b;">&quot;longue chaine&quot;</span>.<span style="color: black;">find</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'chaine'</span><span style="color: black;">&#41;</span> <span style="color: #66cc66;">!</span>= -<span style="color: #ff4500;">1</span>:</pre></div></div>

<p>Au lieu de :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #483d8b;">'chaine'</span> <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #483d8b;">'longue chaine'</span>:</pre></div></div>

<p>Ou alors les programmeurs C qui font :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">for</span> x <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span>, <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>ma_list<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">print</span> ma_list<span style="color: black;">&#91;</span>x<span style="color: black;">&#93;</span></pre></div></div>

<p>Alors qu&#8217;on a :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">for</span> x <span style="color: #ff7700;font-weight:bold;">in</span> ma_list:
    <span style="color: #ff7700;font-weight:bold;">print</span> x</pre></div></div>

<p>Et au besoin:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">for</span> i, x <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">enumerate</span><span style="color: black;">&#40;</span>ma_list<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">print</span> i, x</pre></div></div>

<p>Et à peu près la moitié des programmeurs d&#8217;autres langages qui font :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">if</span> truc == <span style="color: #008000;">True</span>:
    <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>ma_list<span style="color: black;">&#41;</span>:</pre></div></div>

<p>Alors que:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">if</span> truc:
     <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> ma_list:</pre></div></div>

<p>Marche très bien.</p>
<p>Je vous passe les <strong>isintance()</strong> que nous font les programmeurs Java, les check au lieu des gestions des exceptions et les gens qui écrivent les variables en camelCase. <a href="http://python.lycee.free.fr/blog/?p=199">Des gens très compétents font du code horrible</a>.</p>
<p>Certains trouvent que le créateur du langage a été un nazi pour avoir forcé les gens à utiliser l&#8217;indentation et les sauts de ligne ou pour avoir limité les lambdas. Quand je lis le code de certains, j&#8217;ai tendance au contraire à trouver la politique actuelle proche de l&#8217;anarchisme hippie. Interdisons les tabs. Les &#8220;;&#8221; plus de 3 fois d&#8217;affilé. Les nombres de saut de ligne qui ne sont pas standard face au PEP8. En fait faisons des syntax errors sur le PEP8. Et les syntaxes errors déclencheront des chocs électriques via le clavier.</p>
<p>Et on enverra tous ceux qui sont pas d&#8217;accord dans des camps d’entraînement pour qu&#8217;ils puissent tous se concentrer un peu plus sur leur code.</p>
<p>Sinon à quoi ça sert d&#8217;être un BDFL ?</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=4381&amp;md5=fa4c2750b02680399079ef6cfaeee8ca" 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=5586
title: Ne nous invitez pas
uri: Ne-nous-invitez-pas
url: http://sametmax.com/ne-nous-invitez-pas/
content:
<p>Régulièrement on reçoit des invitations Linkedin, Viadeo, Badoo (!) et même Facebook, que ce soit IRL ou pour le blog.</p>
<p>C&#8217;est inutile. Nous ne souhaitons pas rejoindre ces réseaux sociaux / sites de rencontre / moteur de cooptation / dernier nom hype.</p>
<p>Déjà dans ma vie je ne suis ni sur Twitter (c&#8217;est la raison pour laquelle le compte de Sam et Max ne suit personne : Twitter est une corvée qu&#8217;on utilise pour faire connaitre notre blog, pas du tout un outil qu&#8217;on aime utiliser), ni sur Facebook, et encore moins sur LinkedIn ou autre. Ce n&#8217;est donc pas pour les rejoindre sous cette identité.</p>
<p>Ne vous vexez pas si nous n&#8217;acceptons pas vos invitation. Ou si on ne vous suit pas sur telle ou telle plate forme. C&#8217;est juste pas notre truc.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=5586&amp;md5=546cd0d7dea585f6b59a775a77b1b35b" 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=5619
title: Qu’est-ce que Javascript et à quoi ça sert ?
uri: Qu-est-ce-que-Javascript-et-à-quoi-ça-sert
url: http://sametmax.com/quest-ce-que-javascript-et-a-quoi-ca-sert/
content:
<p>La question parait bête, mais je me la suis posé il y a des années. Et personne n&#8217;avait écrit un article pour expliquer ça. Personne. C&#8217;était tellement <a href="http://sametmax.com/bien-expliquer-quelque-chose-les-regles-de-base/">évident</a>.</p>
<p>Cet article est pour toi, étudiant en info, commercial dans une boîte IT ou juste curieux qui trouve que l&#8217;<a href="https://fr.wikipedia.org/wiki/Javascript">article Wikipedia</a> ne veut rien dire.</p>
<h2>Ce que c&#8217;est</h2>
<p>Javascript est un langage de programmation, c&#8217;est une forme de code qui permet, quand on sait l&#8217;écrire, de dicter à l’ordinateur quoi faire.</p>
<p>Le code Javascript ressemble à ça :</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">setTimeout<span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
    <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>truc <span style="color: #339933;">==</span> machin<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000066;">alert</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'Bidule !'</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">100</span><span style="color: #009900;">&#41;</span></pre></div></div>

<p>C&#8217;est du texte. Juste du texte. Comme une autre langue.</p>
<p>On trouve la majorité du code Javascript dans des pages Web, même si vous ne le voyez pas s&#8217;afficher. En effet, c&#8217;est le seul langage qui permette de dicter à un navigateur Web (Internet Explorer, Firefox, Chrome&#8230;) ce qu&#8217;il doit faire sans rien installer. La grande majorité des navigateurs Web &#8220;parlent&#8221; le Javascript.</p>
<h2>Ce qu&#8217;on peut faire avec</h2>
<p>La plupart du code Javascript se trouve dans des pages Web, et sert donc à dire comme la page Web doit réagir. Cela marche ainsi :</p>
<ol>
<li>L&#8217;utilisateur clique sur un lien ou entre une adresse.</li>
<li>Son navigateur charge la page Web. Il voit le texte, les couleurs, les images.</li>
<li>Si la page Web contient du code Javascript, le navigateur lit le code Javascript et suit les instructions du code.</li>
</ol>
<p>Généralement le code Javascript dans une page Web sert à :</p>
<ul>
<li>Faire bouger, apparaitre ou disparaitre des éléments de la page (un titre, un menu, un paragraphe, une image&#8230;).</li>
<li>Mettre à jour des éléments de la page sans recharger la page (changer le texte, recalculer un nombre, etc).</li>
<li>Demander au serveur un nouveau bout de page et l&#8217;insérer dans la page en cours, sans la recharger.</li>
<li>Attendre que l&#8217;utilisateur face quelque chose (cliquer, taper au clavier, bouger la souris&#8230;) et réagir (faire une des opérations ci-dessus suite à cette action).</li>
</ul>
<p>Le code Javascript sert donc à donner du dynamisme à la page. Sans lui, la page ressemble à une page de livre, un peu animée (grâce à un autre langage appelé le CSS), mais qui ne change pas beaucoup.</p>
<p>Par exemple, voici quelques fonctionnalités que l&#8217;on peut voir dans une page Web qui impliquent Javascript :</p>
<ul>
<li><a href="http://jqueryui.com/accordion/">Un menu accordéon.</a></li>
<li><a href="http://jqueryui.com/datepicker/">Un sélecteur de date.</a></li>
<li><a href="http://jqueryui.com/progressbar/">Une barre de progression.</a></li>
</ul>
<p>Cela ne veut pas dire qu&#8217;on ne pourrait pas avoir ces fonctionnalités avec autre chose que Javascript, mais dans notre cas, elles ont été produites avec Javascript.</p>
<p>Certains sites Web ne pourrait tout simplement pas fonctionner sans Javascript. C&#8217;est le cas de Facebook, Youtube ou Twitter qui utilisent le langage pour presque tout leur affichage. La page de recherche de Google, en revanche, peut fonctionner sans Javascript.</p>
<p>Voilà par exemple deux pages similaires. L&#8217;une avec Javascript (cliquez sur le texte pour voir l&#8217;effet) :</p>

<!-- iframe plugin v:2.3 - wordpress.org/extend/plugins/iframe/ -->
<iframe width="100%" height="300" src="http://jsfiddle.net/GBJEx/embedded/result,js,html" allowfullscreen="allowfullscreen" frameborder="0" scrolling="no" class="iframe-class"></iframe>
<p>Et l&#8217;autre sans (cliquez, il ne se passe rien):</p>

<!-- iframe plugin v:2.3 - wordpress.org/extend/plugins/iframe/ -->
<iframe width="100%" height="300" src="http://jsfiddle.net/C4Z9A/embedded/result,js,html" allowfullscreen="allowfullscreen" frameborder="0" scrolling="no" class="iframe-class"></iframe>
<h2>Quelques subtilités</h2>
<p>Le code Javascript est lu et exécuté sur le navigateur Web, donc sur l&#8217;ordinateur de l&#8217;internaute. </p>
<p>C&#8217;est ce qu&#8217;on appelle du code &#8220;côté client&#8221;. Et il ne peut pas interagir directement avec le code &#8220;côté serveur&#8221; (celui qui a produit la page Web); et donc on ne peut pas communiquer directement entre le Javascript côté client et PHP côté serveur par exemple.</p>
<p><strong>Comme l&#8217;internaute a le contrôle de sa machine, il peut choisir de désactiver le support de Javascript sur son navigateur. Dans ce cas, ce dernier ignorera le code Javascript et fera comme si il n&#8217;était pas là. Il verra la page, mais tous les éléments qui fonctionnent avec Javascript ne marcheront pas.</strong></p>
<p>Les pages Web sont aussi parcourues par des navigateurs qui ne supportent pas Javascript, et par des robots qui ne sont pas des navigateurs Web. De nombreux moteur de recherche (comme Google, DuckDuckGo ou Bing) ont en effet de tels robots pour lister toutes les pages Web, et souvent leurs robots ignorent Javascript.</p>
<p>Javascript, quand il est dans le navigateur Web, a aussi cette particularité d&#8217;être un langage limité à ce que le navigateur lui laisse faire. C&#8217;est ce qui le rend assez sécurisé. Mais chaque navigateur a ses particularités et comprend parfois le Javascript différemment. De plus, l&#8217;exécution du code Javascript a pendant longtemps été quelque chose de lent.</p>
<p>Cela a rendu le langage impopulaire, il été évité pour sa difficulté d&#8217;utilisation, ses limites importantes et ses performances basses.</p>
<h2>Javascript moderne</h2>
<p>Aujourd&#8217;hui le langage Javascript est massivement utilisé sur tous les sites Web grand public. Des outils, tel que <a href="http://jquery.com/">jQuery</a>, on été développés pour faciliter son utilisation et les navigateurs sont devenus beaucoup plus efficaces dans son traitement.</p>
<p>La popularité grandissante dans les années 2000 d&#8217;un outil appelé AJAX, qui permet à Javascript de mettre à jour une page sans la recharger, a propulsé le langage sur le devant de la scène. L&#8217;utilisation d&#8217;AJAX rendant, si il elle est bien faite, la consultation du site plus rapide et fluide, on l&#8217;a rapidement retrouvé sur tous les sites les plus fréquentés.</p>
<p><strong>La conséquence est qu&#8217;il est aujourd&#8217;hui impossible de se dire sérieusement développeur Web si l&#8217;on n&#8217;est pas capable d&#8217;écrire un minimum de code Javascript. Si vous voulez développer des sites Web, vous devez apprendre au moins les bases de Javascript. Si vous recrutez un développeur Web, assurez vous qu&#8217;il les connaisse.</strong></p>
<p>Javascript permet aujourd&#8217;hui, avec le support d&#8217;autres technologies (Flash, HTML5, canvas, CSS3, WebGL&#8230;), de faire des choses très évoluées comme de <a href="http://mrdoob.github.io/three.js/">la 3D</a>, de la <a href="http://www.pixastic.com/lib/docs/">manipulation d&#8217;images</a>, <a href="http://buzz.jaysalvat.com/">de sons</a> et <a href="http://popcornjs.org/">de videos</a>. Bientôt, avec des innovations comme WebRTC, Javascript permettra de faire du Peer-to-peer et de la vision conférence à l&#8217;intérieur du navigateur Web :</p>

<!-- iframe plugin v:2.3 - wordpress.org/extend/plugins/iframe/ -->
<iframe width="420" height="315" src="http://www.youtube.com/embed/AThKt13H3Nk" frameborder="0" scrolling="no" class="iframe-class"></iframe>
<p>Si vous voyez un jeu vidéo ou un film dans une page Web, un code Javascript est impliqué quelque part. Le langage a quitté depuis longtemps son statut de technologie &#8220;jouet&#8221; et est actuellement l&#8217;un de ceux qui possèdent le plus de potentiel d&#8217;évolution.</p>
<p>Des innovations importantes sont à attendre du côté de Javascript avec la maturation d&#8217;outils tels que <a href="https://www.youtube.com/watch?v=vpp-8gkPWVE">MeteorJs</a> qui permettent de coder, en Javascript, la génération des pages côté serveur ET le code client des navigateurs, tout en les faisant interagir automatiquement. Si cette phrase ne veut rien dire pour vous, dites vous seulement que c&#8217;est le seul langage à tenir cette promesse actuellement.</p>
<h2>Javascript, en dehors d&#8217;un navigateur Web</h2>
<p>Avec l&#8217;amélioration des performances de Javascript, le langage a été de plus en plus utilisé en dehors du navigateur Web. On le retrouve aujourd&#8217;hui un peu partout :</p>
<ul>
<li>Sur les serveurs, l&#8217;exemple le plus célèbre étant <a href="http://nodejs.org/">NodeJS</a>, un outil qui permet de générer les pages Web avant de les envoyer au navigateur.</li>
<li>Sur les interfaces des ordinateurs, il permet d&#8217;afficher des fenêtres et des boutons (Scripting QT, <a href="https://live.gnome.org/GnomeShell">Gnome Shell</a>).</li>
<li>Sur les téléphones, pour le moment sur <a href="https://www.youtube.com/watch?v=0Uxhd6qk2W8">FirefoxOS</a> et <a href="http://phonegap.com/">PhoneGap</a>, il permet d&#8217;écrire des applications.</li>
</ul>
<h2>Frameworks Javascript</h2>
<p>Javascript est né en tant que technologie minimaliste. Le langage est puissant, mais ne fait pas grand chose de lui-même. Avec sa professionalisation sont apparus ce que l&#8217;on appelle des frameworks, c&#8217;est à dire des collections de code qui rendent le développement en Javascript plus rapide, plus facile et plus puissant.</p>
<p>Sur le navigateur, le plus connu et utilisé est sans aucun doute <a href="http://jquery.com">jQuery</a>. Il est aussi celui que nous préférons utiliser chez Sam et Max, et il n&#8217;existe presque plus de raison de ne pas l&#8217;utiliser aujourd&#8217;hui. Par défaut, si rien d&#8217;évident ne s&#8217;oppose fortement à inclure jQuery, nous recommandons toujours de l&#8217;ajouter d&#8217;office à la première lettre du code Javascript tapée sur un projet Web.</p>
<p>Si vous ne savez pas utiliser jQuery mais devez programmer du Javascript pour une page Web, commencez par apprendre à utiliser jQuery. Coder en Javascript à la main de nos jours, c&#8217;est comme moudre sa farine soi-même, c&#8217;est instructif, mais pas très productif.</p>
<p>Il existe tout de même d&#8217;autres frameworks : Mootools, Prototype.js, YahooUI&#8230; Ceux qui existent encore actuellement sont ceux qui ont survécu à l&#8217;effet mode, et ce sont tous des outils aujourd’hui solides.</p>
<p>Ensuite il y a des bibliothèque spécialisées dans des problématiques telles que le routing, la manipulation de modèles, le templating, etc. Encore une fois, si ces termes ne vous parlent pas, c&#8217;est que vous n&#8217;avez pas encore besoin de ces bibliothèques. On retrouve dans le lot <a href="http://backbonejs.org/">backbone.js</a>, <a href="https://github.com/jokry/spinejs">spine.js</a>, <a href="https://github.com/dschnare/mustachejs">mustache.js</a> et bien d&#8217;autres.</p>
<p>Des frameworks hybrides couvrant de nombreuses problématiques à la fois sont arrivés ces dernières années, notamment <a href="http://knockoutjs.com/">knockout.js</a> de Microsoft et <a href="http://angularjs.org/">AngularJS</a> de Google qui sont encore très jeunes mais qui méritent d&#8217;être suivis de prêt.</p>
<h2>Les mauvais côtés de Javascript</h2>
<p>Malgré ma lucidité concernant l&#8217;importance grandissante de Javascript, j&#8217;aimerais partager avec vous des choses que les enthousiastes ne vous disent pas.</p>
<p>D&#8217;abord, c&#8217;est un langage extrêmement laid. Ça va vous sembler futile, mais ça se traduit par un temps d&#8217;apprentissage du langage plus élevé. Un temps de relecture BEAUCOUP plus élevé (et on lit le code des centaines de fois par jour). Un temps de debuggage plus long également. Et des erreurs plus nombreuses car le JS est très permissif. Bref, c&#8217;est un langage très improductif si on le compare à Ruby, Python ou même à PHP.</p>
<p>Pour donner une idée de la chose, voici un code Javascript que peut produire un débutant pour écrire la fameuse chanson <a href="http://99-bottles-of-beer.net/">99 bottle of beers</a>:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #000066; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">var</span> i <span style="color: #339933;">=</span> <span style="color: #CC0000;">99</span> <span style="color: #339933;">;</span> i <span style="color: #339933;">&gt;</span> <span style="color: #CC0000;">0</span> <span style="color: #339933;">;</span> i<span style="color: #339933;">--</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
&nbsp;
  j <span style="color: #339933;">=</span> i <span style="color: #339933;">-</span> <span style="color: #CC0000;">1</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>i <span style="color: #339933;">!=</span> <span style="color: #CC0000;">1</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> 
    icase <span style="color: #339933;">=</span> <span style="color: #3366CC;">&quot;bottles&quot;</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> 
    icase <span style="color: #339933;">=</span> <span style="color: #3366CC;">&quot;bottle&quot;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>j <span style="color: #339933;">!=</span> <span style="color: #CC0000;">1</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    jcase <span style="color: #339933;">=</span> <span style="color: #3366CC;">&quot;bottles&quot;</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>
    jcase <span style="color: #339933;">=</span> <span style="color: #3366CC;">&quot;bottle&quot;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  console.<span style="color: #660066;">log</span><span style="color: #009900;">&#40;</span>i <span style="color: #339933;">+</span> <span style="color: #3366CC;">&quot; &quot;</span> <span style="color: #339933;">+</span> icase <span style="color: #339933;">+</span> <span style="color: #3366CC;">&quot; of beer on the wall,&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  console.<span style="color: #660066;">log</span><span style="color: #009900;">&#40;</span>i <span style="color: #339933;">+</span> <span style="color: #3366CC;">&quot; &quot;</span> <span style="color: #339933;">+</span> icase <span style="color: #339933;">+</span> <span style="color: #3366CC;">&quot; of beer,&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  console.<span style="color: #660066;">log</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;Take 1 down, pass it around,&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>j <span style="color: #339933;">!=</span> <span style="color: #CC0000;">0</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    console.<span style="color: #660066;">log</span><span style="color: #009900;">&#40;</span>j <span style="color: #339933;">+</span> <span style="color: #3366CC;">&quot; &quot;</span> <span style="color: #339933;">+</span> jcase <span style="color: #339933;">+</span> <span style="color: #3366CC;">&quot; of beer on the wall.&quot;</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>
    console.<span style="color: #660066;">log</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;No more bottles of beer on the wall!&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  console.<span style="color: #660066;">log</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Et voici l&#8217;équivalent (littéral) en Python :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">xrange</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">99</span>, <span style="color: #ff4500;">0</span>, -<span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>:
&nbsp;
    j = i - <span style="color: #ff4500;">1</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">if</span> i <span style="color: #66cc66;">!</span>= <span style="color: #ff4500;">1</span>:
        icase = <span style="color: #483d8b;">&quot;bottles&quot;</span>
    <span style="color: #ff7700;font-weight:bold;">else</span>:
        icase = <span style="color: #483d8b;">&quot;bottle&quot;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">if</span> j <span style="color: #66cc66;">!</span>= <span style="color: #ff4500;">1</span>:
        jcase = <span style="color: #483d8b;">&quot;bottles&quot;</span>
    <span style="color: #ff7700;font-weight:bold;">else</span>:
        jcase = <span style="color: #483d8b;">&quot;bottle&quot;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">&quot;%s %s of beer on the wall&quot;</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span>i, icase<span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">&quot;%s %s of beer,&quot;</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span>i, icase<span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">&quot;Take 1 down, pass it around,&quot;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">if</span> j:
        <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">&quot;%s %s of beer on the wall.&quot;</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span>j, jcase<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: #483d8b;">&quot;No more bottles of beer on the wall!&quot;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">print</span></pre></div></div>

<p>En plus d&#8217;être plus plus d&#8217;être plus long de 50 caractères, le code Javascript comporte deux bugs potentiels : les variables non déclarées fonctionnent, mais sont partagées avec tout le reste du code. Le <code>console.log</code> va lui aussi fonctionner sur un serveur et sur certains navigateurs, mais fera planter d&#8217;autres navigateurs qui n&#8217;ont pas accès à cet objet. On peut le remplacer par <code>document.writeln</code> mais alors le code ne marchera pas sur un serveur.</p>
<p>Les prérequis pour coder un simple bout de code Javascript sans erreur sont plus élevés, la vigilance demandée est plus grande.</p>
<p>Ensuite, il est difficile de trouver de bons développeurs Javascript. Les profils les plus courants sont des designers forcés à faire un peu de JS, ou des codeurs PHP qui de temps en temps insèrent du JS dans leurs pages. Les spécialistes Javascript sont rares, chers et pas faciles à embaucher.</p>
<p>D&#8217;ailleurs, pour former quelqu&#8217;un ou se former à Javascript, les ressources sont spartiates. Je ne parle pas des milliers de scripts tout fait prêts à être utilisés. Ça il y en a plein. Je parle de cours pour devenir un codeur sérieux, et sortir de la relation d&#8217;amateurisme que la majorité des développeurs Web ont avec Javascript.</p>
<p>Côté navigateur, le Javascript est mûr. En revanche, en dehors du navigateur, c&#8217;est une technologie qui est encore dans son enfance. Oui, je parierai cher qu&#8217;il va devenir très dominant dans les prochaines années. Mais en attendant, <a href="http://sametmax.com/non-nodejs-nest-pas-mature/">ceux qui s&#8217;y mettent maintenant vont payer les pots cassés</a> : libs pas testées, mal documentées, incompatibles, maintenues avec des baguettes&#8230; quand elles existent.</p>
<p>Rien qu&#8217;installer de quoi coder en Javascript sur sa machine est une plaie : sous Linux et Mac, Ruby et Python sont installés par défaut. Javascript demande des étapes en plus. Sous Windows, c&#8217;est le parcours du combattant.</p>
<p>En clair : mettre trop de billes dans Javascript coûte cher, et c&#8217;est pour cela que je m&#8217;en tiens à développer avec sur des pages Web qui est son habitat naturel puisqu&#8217;il n&#8217;y a besoin de rien installer. C&#8217;est la raison de sa popularité initiale, et on est en train de faire exactement l&#8217;inverse en forçant son portage partout ailleurs.</p>
<p>Javascript n&#8217;est pas adapté à tout, et en ce moment, on veut le mettre à toutes les sauces. C&#8217;est à mon sens préjudiciable, très fortement influencé par un effet de mode, et met de côté d&#8217;excellents autres langages qui seraient beaucoup plus adaptés. Aussi, si vous devez faire de la programmation serveur ou d&#8217;interface graphique, je vous recommande plutôt Ruby ou Python, avec une préférence pour ce dernier somme toute biaisée par l&#8217;usage intensif qu&#8217;on en fait. </p>
<p>En prime ils vous rendront service pour le scripting, les traitements et l&#8217;analyse de données, le prototypage, et plein d&#8217;autres situations auxquelles vous n&#8217;aviez pas pensé. Ce sont des langages créés à l&#8217;origine pour être généralistes, pas adaptés durant les dernières années parce qu&#8217;ils ont le vent en poupe (Python est plus vieux que Java&#8230;).</p>
<p>Cela ne vous dispense pas de capitaliser sur des talents en Javascript en plus de ceux existant. Cela risque d&#8217;être plus qu&#8217;utile pour le futur.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=5619&amp;md5=f169714f23643132c8507834ff6a0602" 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=5652
title: Invalid cross-device link
uri: Invalid-cross-device-link
url: http://sametmax.com/invalid-cross-device-link/
content:
<p>Les erreurs d&#8217;upload de fichier, c&#8217;est 99% de problèmes de droit d&#8217;accès et d&#8217;espace disque. Mais de temps à autres, on tombe sur des petites saloperies bien vicelardes comme ce code anodin :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #dc143c;">os</span>.<span style="color: black;">rename</span><span style="color: black;">&#40;</span>uploaded_tmp_file, destination<span style="color: black;">&#41;</span></pre></div></div>

<p>Ce snippet, comme vous l&#8217;aurez compris, prend simplement un fichier qui vient d&#8217;être uploadé et le déplace vers un autre dossier où il sera traité, chouchouté, encodé, et mis en ligne.</p>
<p>Sauf que la ligne en question nous a valu un cryptique :</p>
<p><code>IOError: Invalid cross-device link</code></p>
<p><a href="http://sametmax.com/debugger-en-python-les-bases-de-pdb/">PDB</a> nous confirme le merdier, même en le faisant à la main. Pourtant la commande bash <code>MV</code> fait le déplacement du fichier sans problème.</p>
<p>User / group ? Checked.</p>
<p>Permission en lecture écriture ? Checked.</p>
<p>SEL linux ? Désactivé depuis longtemps.</p>
<p>Quid alors ?</p>
<p><a href="http://mail.python.org/pipermail/python-list/2005-February/323335.html">Les archives de la mailling list</a> de Python nous offre une réponse à la question, que je vous traduis :</p>
<blockquote><p>mv est un programme étonnamment complexe, tandis que os.rename est un wrapper autour de rename(2) qui est probablement documenté sur ton système comme retournant EXDEV dans ces circonstances.</p>
<p>os.xxx est généralement une surcouche assez fine autour de ce que ton OS fournit, et en hérite toutes les limites. Pour certains actions, os.shutil fournit quelque chose qui se situe entre os.xxx et os.system(&#8220;xxx&#8221;) en terme de complexité et de capacité.</p></blockquote>
<p>Je l&#8217;ai traduis en français, maintenant je vous la refais en langage humain : <code>os.rename</code> ne fait vaguement qu&#8217;appeler la commande <code>rename</code>, qui n&#8217;est pas très puissante, et notamment qui est incapable de gérer un déplacement de fichier d&#8217;une partition à une autre. Or dans notre cas, notre dossier temporaire était sur une partition séparée pour des raisons de perfs.</p>
<p>La solution est d&#8217;utiliser <code>shutil</code>, un module un peu plus lent, mais surtout de plus haut niveau qui se charge des détails comme la nature et l&#8217;origine du fichier et de sa destination. </p>
<p>Bref, la solution est tout simplement de faire :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #dc143c;">shutil</span>.<span style="color: black;">move</span><span style="color: black;">&#40;</span>uploaded_tmp_file, destination<span style="color: black;">&#41;</span></pre></div></div>

<p>Tout ça pour ça, oui, mais c&#8217;est ce qui arrive quand une abstraction ne fait plus son boulot dans un langage de haut niveau où on a l&#8217;habitude que tout soit automatisé.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=5652&amp;md5=f4e22e907d59336b3c3aaf89a65e4e9f" 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=5641
title: Changement du cache du blog
uri: Changement-du-cache-du-blog
url: http://sametmax.com/changement-du-cache-du-blog/
content:
<p>Vu qu&#8217;on est des feignasses et qu&#8217;on a pas envie de tweaker le blog jusqu&#8217;à ce que performances s&#8217;en suivent, on a fait les bourrins en mettant un gros <a href="sametmax.com/initiation-a-varnish-accelerer-un-blog-wordpress/">varnish</a> en front.</p>
<p>On a reçu de nombreuses remarques comme quoi on ne voyait pas si les commentaires étaient postés et autres détails qui rendaient la consultation du blog fort confuse.</p>
<p>On est pas devenu moins fainéant entre temps, mais il se trouve que je suis tombé par hasard sur <a href="http://wordpress.org/extend/plugins/wordpress-varnish/">ce plugin WordPress</a> (ou alors quelqu&#8217;un me l&#8217;a recommandé, je sais plus) et j&#8217;ai trouvé la motivation pour l&#8217;installer ce matin.</p>
<p>Normalement il devrait invalider le cache à chaque fois qu&#8217;on met à jour un article ou que quelqu&#8217;un poste un commentaire.</p>
<p>À voir si ça plombe pas les perfs mais normalement ça devrait aller, on a eu à peine 4,758 comments depuis le lancement du blog, ça fait moins d&#8217;un comment à l&#8217;heure, on devrait survivre.</p>
<p>Si vous constatez que c&#8217;est mieux, faites le nous savoir, on aura au moins l&#8217;impression d&#8217;avoir fait notre BA.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=5641&amp;md5=2ade60002d8f7151d909eecf1ec22d07" 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=5646
title: I love les piles USB
uri: I-love-les-piles-USB
url: http://sametmax.com/i-love-les-piles-usb/
content:
<p>On est en 2013, et on a encore tous des bidules à pile. Parce que les piles c&#8217;est pratique. On peut les changer instantanément par des piles neuves au lieu d&#8217;attendre que ça recharge. On peut trouver d&#8217;autres piles du même format facilement partout dans le monde (bonne chance pour la batterie de votre joujou dernier cri, quand il daigne vous laissez accès à elle). Et si vous avez oublié le chargeur de vos piles (car vous utilisez des rechargeables, hein ?), vous avez le joker d&#8217;en acheter ponctuellement des jetables.</p>
<p>C&#8217;est beau. C&#8217;est low tech.</p>
<p>Parmi mes jouets, j&#8217;ai la même souris que <a href="http://sametmax.com/le-cadeau-de-noel-est-arrive/">foxmask</a>, qui fonctionne à pile et sans fil, en touffe bleue. Et ce merveilleuse gadget vient avec un cable USB pour fonctionner quand même quand mes AA tombent en rade.</p>
<p>C&#8217;est beau. C&#8217;est hi-tech.</p>
<p>Néanmoins se trimbaler avec un chargeur NiMH dans la cabasse, c&#8217;est un tantinet ennuyeux. </p>
<p>La solution est fournit par <a href="http://www.usbcell.com">USB cell</a> a qui j&#8217;ai acheté ces fantastiques piles rechargeables en USB. </p>
<p>Sans chargeur.</p>
<p>Ou plutôt avec le chargeur et le port USB intégré dans chaque pile ! </p>
<p>Top délire méga groove :</p>
<div id="attachment_5650" class="wp-caption aligncenter" style="width: 471px"><a href="media/7d9e58f1.2013-04-08-152054.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2013/04/2013-04-08-152054.jpg"><img class=" wp-image-5650  " title="Bon désolé, j'ai plus d'APN" src="media/7d9e58f1.2013-04-08-152054.jpg" data-original-source="http://sametmax.com/wp-content/uploads/2013/04/2013-04-08-152054.jpg" alt="Photo de piles USB rechargeables" width="461" height="368" /></a><p class="wp-caption-text">Bon désolé, j&#39;ai plus d&#39;APN</p></div>
<p>&nbsp;</p>
<p>*</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=5646&amp;md5=1f4f0ecdf100e97d4e469b51599b3107" 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=5683
title: Historique bash récent
uri: Historique-bash-récent
url: http://sametmax.com/historique-bash-recent/
content:
<p>Je plagie <a href="http://pydanny.com/20130410-history-of-my-most-used-shell-commands.html">PyDanny</a> en affichant ici mon historique des commandes les plus utilisées récupéré grâce à :</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ <span style="color: #7a0874; font-weight: bold;">history</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">awk</span> <span style="color: #ff0000;">'{a[$2]++ } END{for(i in a){print a[i] &quot; &quot; i}}'</span><span style="color: #000000; font-weight: bold;">|</span><span style="color: #c20cb9; font-weight: bold;">sort</span> <span style="color: #660033;">-rn</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;">20</span></pre></div></div>

<p>L&#8217;exercice consiste à commenter chaque entrée, donc acte :</p>
<pre>100 ./manage.py # Jamie Foxx
71 sudo         # Make me a sandwich (then apt-get upgrade)
56 cd           # j'ai beaucoup de projets différents
41 ipython      # Voilà ce que c'est d'être dev Python...
40 ssh          # ... sur des projets Web
37 py.test      # Ben oui, je fais des tests !
37 ls           # Comment ça IOError ?
34 gs           # Alias de Git status :-)
26 ga           # Merveilleux SCMBreeze, installez le
24 pip          # requests, ipdb, path.py, peewee...
24 co           # git commit -m "`echo "$*" | sed -e 's/^./\U&#038;\E/g'`"
22 vi           # Presque que pour les config d'nginx
21 python       # Quand je fais des tests pour le blog
17 [censored]   # Le nom d'un projet de site de Cul
15 workon       # Ca devrait être + élévé, mais j'ai ajouté l'autovirtualenv
15 grin         # J'aime pas "rechercher dans tous les fichiers" sur ST2
11 tail         # Une longue session de debuggage via log d'erreurs
10 ipython3     # Migration vers Python 3 en cours
9 wget          # Pas envie de toucher ma souris</pre>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=5683&amp;md5=6ab5299296ba3fd0c5341737dcd07af1" 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=5757
title: 10 lieux de baise pas glop
uri: 10-lieux-de-baise-pas-glop
url: http://sametmax.com/10-lieux-de-baise-pas-glop/
content:
<p>Remercions la télé pour le nombre de clichés de cul qu&#8217;elle a propagé, et notamment toutes ces parties de jambes en l&#8217;air torrides dans des endroits bien loin de votre king size bed. Des fois, vouloir se l&#8217;a jouer exotique n&#8217;a pas l&#8217;effet escompté.</p>
<h3>Le Hammam</h3>
<p>C&#8217;était en Espagne, on sortait d&#8217;un jacuzzi plein d&#8217;oranges (pourquoi il avait foutu des oranges dans le bain ?), et on a rejoint le hammam du Spa. Personne en vu, c&#8217;était trop tentant.</p>
<p>Sauf qu&#8217;après s&#8217;être ramolli dans de l&#8217;eau chaudes pleines de bulles, la levrette en rafale dans une salle à 10000 degré dans laquelle on respire de la vapeur d&#8217;eau c&#8217;est dur. Mon cœur à pas du tout aimé, et j&#8217;ai du m’arrêter.</p>
<p>Pour la pipe ça doit être pas mal ceci dit.</p>
<h3>La baignoire</h3>
<p>Autant la douche, si on a de quoi tenir le pommeau tout seul et un débit d&#8217;eau généreux, ça le fait (ma salle de bain est une douche italienne avec une vitre transparente qui donne sur un miroir&#8230;). Autant se serrer dans ces putains de baignoires françaises avec les bouts du robinets qui dépassent, c&#8217;est mort. Impossible de copuler là dedans.</p>
<h3>La plage</h3>
<p>Le mythe. Le truc le plus bidon par excellence. Supposons que l&#8217;on ne se soit pas baigné et donc pas recouvert de sel, les cheveux dégueulasses et un goût d&#8217;algue dans la bouche. Admettons qu&#8217;il n&#8217;y ai pas d&#8217;enfants de 6 ans et leurs parents psychorigides qui traînent (voir qu&#8217;on soit sur une plage naturiste). Subodorons que nous sommes à l&#8217;ombre, sans le soleil qui rouge la peau et sans cette crème de protection dégueulasse qui dégoûterait un teckel de lécher un téton plein de Nutella.</p>
<p>Ça fait beaucoup de conditions, mais soit.</p>
<p>Il reste le sable. Cette saloperie de sable. Qui se glisse partout, même quand on a une serviette qui reste de toute façon 23 seconds en place avant de rejoindre les crabes pendant que chaque grain de mica vous irrite les zones érogènes que vous avez tenté de frictionner. Et si vous avez le malteur d&#8217;en avoir qui se met sur la capote&#8230;</p>
<h3>Dans le lit d&#8217;un pote pendant une soirée</h3>
<p>Vous êtes bourré. Elle aussi. Tout le reste de la fête aussi. Alors personne ne va vous voir aller tranquillement dans la chambre à Nico pour un petit quicky. Cette fameuse chambre dans laquelle il y a tous les manteaux entassés de tous les invités.</p>
<p>Vous foutez tout par terre, et faites fît l&#8217;odeur de transpiration qui émane des draps que ce petit con d&#8217;étudiant en histoire de l&#8217;art n&#8217;a pas lavé depuis son mémoire sur l&#8217;icônification du consumérisme de 1981 à 1983. Vous ignorez aussi les poils torsadés qui traînent ici et là. Nico est bouclé, c&#8217;est peut être des cheveux.</p>
<p>Mais la porte ne ferme pas à clé. Et si ça excite peut être mademoiselle cette idée que quelqu&#8217;un peut arriver à tout moment, n&#8217;empêche que quand le quelqu&#8217;un entre dans la salle pour récupérer son briquet dans la poche de sa veste, elle arrête tout. Et ne reprend pas.</p>
<p>Pas assez bourrée, sans doute.</p>
<h3>Dans les chiottes d&#8217;une boîte</h3>
<p>C&#8217;est dégueu, ça pu, on peut s&#8217;appuyer sur rien. Je dois vous faire un dessin ? Il vaut mieux rien faire que faire ça, sérieux.</p>
<p>Le seul point fort c&#8217;est le côté &#8220;yes, je viens de rencontrer une nana, et je peux déjà ma l&#8217;envoyer tout de suite&#8221;. Allez aux putes, ça vous coûtera à peine plus que le prix de l&#8217;entrée et des consos.</p>
<h3>Dans la voiture</h3>
<p>Certes, c&#8217;est une nécessité logistique. Et oui, tout le monde l&#8217;a fait, et on le refera, parce que des fois il y a juste pas le choix, pas le temps ou la motiv. Mais il n&#8217;y a pas de position confortable sur ces sièges pourris. Et on finit toujours par appuyer par erreur sur le klaxon. Sauf quand on est à l&#8217;arrière où il manque toujours la place pour un membre : le cul, les jambes, la têtes. Deux maximum au choix.</p>
<p>Ou alors il faut une limo. Là, ok.</p>
<h3>Dans la paille</h3>
<p>Qu&#8217;on se le dise, la paille, ça gratte. Ça gratte pendant, et ça gratte après. On en a dans les cheveux, dans les vêtements, les chaussures&#8230; On en retrouve encore des petits bouts le soir, et avec un peu de chance des morceaux dans le lit le lendemain matin. Alors oui c&#8217;est confortable. Oui c&#8217;est pratique si la miss est pas allergique, mais bon, si on est amateur de blé, autant le faire dans un champ.</p>
<h3>En la portant contre un mur</h3>
<p>J&#8217;ai rien contre les murs. J&#8217;adore les murs. Y en a de très bien. On peut faire des tas de choses géniales avec une bonne surface verticale solide et rassurante.</p>
<p>Mais combien de mecs ont la force pour porter une nana pendant tout un coït à la force de ses petits bras ?</p>
<p>Généralement ça donne un truc comme ça:</p>
<p>Étape 1 : lui lancer un regard sauvage, la soulever et la plaquer contre le premier plan opposable qu&#8217;on trouve.</p>
<p>Étape 2 : se lancer dans une expédition exploratoire de tout le territoire, occuper les places fortes et adapter son rythme à la campagne.</p>
<p>Étape 3 : comprendre que la meuf n&#8217;a aucune intention de s’accrocher avec ses bras et que vos deltoïdes vont faire tout le boulot.</p>
<p>Étape finale : au bout de quelques minutes, ralentir, se rendre compte que ça va finir en flamby et trouver une excuse pour changer de position en gardant la face.</p>
<p>Facultatif : Réaliser que c&#8217;est un mur en crépi quand elle hurle que tu lui arrache le dos. Oui, c&#8217;est vécu, oui.</p>
<h3>Sur ton ordinateur portable neuf</h3>
<p>Qu&#8217;on avait pas vu sous la couette. Très surfait. Et très cher aussi.</p>
<p>Existe également en version tablette.</p>
<h3>Dans une chambre avec un chat</h3>
<p>Il regarde. Et il comprend. Et vous savez qu&#8217;il regarde et qu&#8217;il comprend. Et il sait que vous savez. </p>
<p>Vous pensez à autre chose, et là le chat saute sur le lit pour bien vous rappeler qu&#8217;il est là, comme quand vous travaillez sur votre laptop, sauf que là que ne pouvez pas lui donner un coup de latte car c&#8217;est pas VOTRE chat.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=5757&amp;md5=f814952e418d21d61aa94b36694da237" 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=5663
title: Soyez paranos avec les codes de suppression
uri: Soyez-paranos-avec-les-codes-de-suppression
url: http://sametmax.com/soyez-paranos-avec-les-codes-de-suppression/
content:
<p>L&#8217;informatique est généralement une discipline rationnelle (sauf bien entendu dans le cas de l&#8217;administration d&#8217;un système Windows), et pondre un bout de code pour un cas d&#8217;utilisation qui n&#8217;aura jamais lieu n&#8217;est pas vraiment la qualité première qu&#8217;on demande à un développeur.</p>
<p>Sauf. Sauf dans un cas.</p>
<p>Dans le cadre d&#8217;un code de suppression.</p>
<h3>Au delà de RM</h3>
<p>Un code de suppression peut se cacher derrière bien plus qu&#8217;un <code>remove</code> :</p>
<ul>
<li>Renommer ou déplacer une donnée ou un fichier.</li>
<li>Écrire par dessus ou à la suite du conteneur de données (tel qu&#8217;un fichier ou une table).</li>
<li>Mettre à jour la donnée elle-même.</li>
</ul>
<p>C&#8217;est valable dans les scripts shell, mais également dans les scripts Python (ou tout langage qui vous sert à faire des opérations sur des systèmes critiques) : <code>os.remove</code>, <code>os.rename</code>, <code>shutil.move</code>, <code>open('file', 'w').write('...')</code>, etc.</p>
<p>Mais c&#8217;est aussi toutes les requêtes SQL en écriture.</p>
<p>Les codes à surveiller le plus sont ceux qui peuvent entrainer une suppression massive :</p>
<ul>
<li><code>SELECT * UPDATE</code> ou <code>DROP table</code></li>
<li><code>rm -fr</code> ou tout code manipulant un fichier matché avec un glob (*)</li>
<li><code>os.removes</code>, <code>shutil.rmtree</code>, tout code qui manipule un fichier dans une boucle ou un appel récursif</li>
</ul>
<p>Mais tous les autres restent importants si tant est que la donnée cible est critique (contenu de l&#8217;utilisateur, donnée non récupérable par un autre moyen ou alors de manière lente et coûteuse). Même quand vous avez un backup dont vous êtes certains de la perfection &#8211; et franchement je me méfie toujours des backups &#8211; une restauration, c&#8217;est long, ça implique souvent une interruption de service ou au moins une dégradation, et de toute façon c&#8217;est du taff dont vous n&#8217;aviez vraiment pas besoin.</p>
<h3>Pensez au petit fils de Murphy et François Perrin</h3>
<p>Quand on a un petit site ou un logiciel en local de taille moyenne, on ne pense pas à ce genre de choses. Mais quand on travaille avec des grosses DB qui sont tout le temps sollicitées et des systèmes de fichiers qui sont blindés de Tera octets de contenus qui prennent des semaines à uploader sur un serveur (j&#8217;ai bien dis des SEMAINES), on ne veut pas que ça disparaisse.</p>
<p>La réplication et le load balancing peuvent vous sauver d&#8217;un plantage matériel ou d&#8217;un bug logique. Mais une corruption de données en cascade, ça se propage à tout un système. Et un RM massif, c&#8217;est exactement ça, surtout à l&#8217;heure des surcouches d&#8217;abstraction d&#8217;outils de haut niveau automatiques.</p>
<p>Alors vous allez me dire que les chances que ça arrive sont minimes. En fait votre code est propre, vous faites des checks normaux, il n&#8217;y a pas d&#8217;injections possibles, tout est sanitizé, bref, il n&#8217;y a pas de raison que ça chie.</p>
<p>Et vous n&#8217;auriez pas tort, si il n&#8217;y avait pas 2 importantes particularité du monde de l&#8217;informatique :</p>
<ul>
<li>En informatique tout est multiplié par des milliards en quelque seconde. Une opération qui à très peu de chance d&#8217;arriver (une chance sur 10 milliards, c&#8217;est plus bas que de gagner au loto), peut donc survenir très facilement puisque l&#8217;opération est répétée un très grand nombres de fois en un temps très court.</li>
<li>Vous n&#8217;avez pas la main sur tout le système. Ce n&#8217;est pas sous votre contrôle. La complexité matérielle est logiciel est telle que vous n&#8217;en comprenez qu&#8217;un centième, et ce blob néo punk dont vous devez vous occuper est en interaction avec un environnement technique et humain gigantesque, parfaitement imprévisible, qui se renouvelle sans cesse.</li>
</ul>
<p>Et comme la gravité des conséquences d&#8217;une merde de suppression massive est du genre &#8220;Code Rouge&#8221; dans &#8220;28 semaines plus tard&#8221;, vous ne pouvez pas vous permettre de ne pas blinder les suppressions.</p>
<p>Quelques scénarios à la con qui peuvent vous tuer sur un code aussi con que ça :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">from</span> fabric <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">cd</span>, sudo
&nbsp;
<span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">conf</span> <span style="color: #ff7700;font-weight:bold;">import</span> settings
&nbsp;
&nbsp;
...
&nbsp;
<span style="color: #ff7700;font-weight:bold;">for</span> content <span style="color: #ff7700;font-weight:bold;">in</span> contents:
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> content.<span style="color: black;">published</span>:
&nbsp;
        <span style="color: #ff7700;font-weight:bold;">with</span> <span style="color: #dc143c;">cd</span><span style="color: black;">&#40;</span>settings.<span style="color: black;">MEDIA_ROOT</span><span style="color: black;">&#41;</span>:
            sudo<span style="color: black;">&#40;</span><span style="color: #483d8b;">'rm -fr {}'</span>.<span style="color: black;">format</span><span style="color: black;">&#40;</span>content.<span style="color: black;">path</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>A priori, rien de dangereux : vous contrôlez vos settings, vous contrôlez votre base de données, pas de malveillances, vous vérifiez que le contenu à expiré. Que peut-il arriver de mauvais ?</p>
<p>Plein de choses :</p>
<ul>
<li>Vous avez merdé dans un merge Git octopussien entre votre fichier, celui de votre collègue qui vient de partir en retraite et celui de la démo de l&#8217;open coffee dans laquelle vous avez fait un quick fix après un effet démo bien humiliant. Il se glisse un early <code>return</code> est inséré dans la propriété <code>content.published</code> et comme Python retourne <code>None</code> par défaut, tous les contenu sont supprimés.</li>
<li>Vous êtes fatigués, vous avez oublié de changer le <code>local_settings</code> et <code>MEDIA_ROOT</code> n&#8217;a pas la même valeur. Vous effacez dans le répertoire de prod ou lieu du répertoire de test.</li>
<li><code>content.path</code> est éditable dans l&#8217;admin privée de Django. En restaurant un formulaire avec une extension Firefox, il se glisse une étoile que vous ne remarquez pas dans le nom du contenu automatiquement utilisé pour créer le chemin de fichier, et vous faites un <code>rm -fr</code> avec un beau <code>*</code> dedans.</li>
<li>Vous discutez avec votre voisin et tapez du code dans le shell en prod pour faire une migration bénin après vous êtres dit que &#8220;c&#8217;est pas la peine de lancer south pour ça&#8221;. Grâce à la magie du cerveau humain vous tapez ce qu&#8217;il vous dit au lieu ce la commande que vous vouliez taper, et la moitié de votre <code>try</code> est excécuté, mais pas le code du <code>except</code>, par contre le <code>finally</code> a bien tout défoncé. Pardon, nettoyé.</li>
<li>Vous avez un stagiaire.</li>
</ul>
<p>Le plus drôle, c&#8217;est quand plusieurs trucs improbables se cumulent, là on peut faire des combos qui déchirent bien toute l&#8217;infrastructure.</p>
<p>Les tests unitaires et la sanitization en vous protégera pas de la fatigue, inattention, l’éternuement au dessus en pleine session SSH, le chat qui saute sur le clavier&#8230; Souvenez-vous de la mouche dans Brazil.</p>
<h3>Vous protéger contre vous même</h3>
<p>Sur des codes comme ça, il faut donc prendre des mesures supplémentaires. Faire les vérifications qu&#8217;on ne fait jamais, de ce qui ne peut pas arriver.</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">&nbsp;
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">re</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">from</span> fabric <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">cd</span>, sudo
&nbsp;
<span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">conf</span> <span style="color: #ff7700;font-weight:bold;">import</span> settings
&nbsp;
&nbsp;
...
&nbsp;
<span style="color: #ff7700;font-weight:bold;">for</span> content <span style="color: #ff7700;font-weight:bold;">in</span> contents:
&nbsp;
    <span style="color: #808080; font-style: italic;"># stylistiquement on ne fait jamais ça en Python, mais ici, on ne prend</span>
    <span style="color: #808080; font-style: italic;"># pas le risque</span>
    <span style="color: #ff7700;font-weight:bold;">if</span> content.<span style="color: black;">expired</span> == <span style="color: #008000;">False</span>: <span style="color: #808080; font-style: italic;"># None != False</span>
&nbsp;
        <span style="color: #808080; font-style: italic;"># on évite autant que possible les CD qui peuvent merder grave</span>
        path = <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">join</span><span style="color: black;">&#40;</span>settings.<span style="color: black;">MEDIA_ROOT</span>, content.<span style="color: black;">path</span><span style="color: black;">&#41;</span>
&nbsp;
        <span style="color: #808080; font-style: italic;"># on check strictement le chemin qu'on va degommer avec une regex qui</span>
        <span style="color: #808080; font-style: italic;"># ne laisse pas la place &quot;/&quot;, &quot;/bidule/*&quot; et autre &quot;..&quot;</span>
        <span style="color: #808080; font-style: italic;"># et qui réplique au plus prêt la structure de l'arbo qu'on vise</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #dc143c;">re</span>.<span style="color: black;">match</span><span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'^regex_de_nazi$'</span>, path<span style="color: black;">&#41;</span>:
            sudo<span style="color: black;">&#40;</span><span style="color: #483d8b;">'rm -fr {}'</span>.<span style="color: black;">format</span><span style="color: black;">&#40;</span>path<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Idéalement il faudrait avoir les droits nécessaires pour éviter le <code>sudo</code>. On peut même exceptionnellement casser le DRY en mettant <code>MEDIA_ROOT</code> en dur dans cette fonction. C&#8217;est à double tranchant, mais on ne vit pas dans un monde idéal.</p>
<p>Une regex qu&#8217;on a en production ressemble à ça:</p>
<p>re.match(r&#8217;^/[\w-]+/[\w-]+/\d/\d/\d/\d/\d/\d+$&#8217;, path):</p>
<p>Qui ne laissera passer qu&#8217;une suppression d&#8217;un truc qui à la forme &#8220;/1nom-de_dossier/una_autre-nom/8/1/9/3/5/890709&#8243;. Pas une arbo plus courte ou plus longue. Pas d&#8217;étoiles ou de guillemets. Pas un dossier qui ne contienne pas exactement cet enchaînent de sous-dossiers numériques.</p>
<p>Et ce, malgré le fait que path est généré depuis un ID extrait d&#8217;un auto ID en DB (non accessible dans l&#8217;admin). Parce qu&#8217;on ne sait jamais. Et on ne peut pas se permettre que ça pète.</p>
<p>Pareil pour le SQL, n&#8217;hésitez pas à faire des requêtes en plus avant le DELETE pour voir si les données sont cohérentes. La plupart du temps on s&#8217;en branle si une suppression est lente.</p>
<p>Bref, les bonnes pratiques que sont de bien nettoyer ses données, de bien setter ses permissions et de ne pas tout lancer à 3 heures du matin après une session de debugging de 6 heures au Red Bull sont toujours des priorités. Cependant souvenez vous que vous êtes humains, vous allez faire des conneries, les autres aussi.</p>
<p>Vous allez avoir un système imparfait (non, vous n&#8217;avez pas mis des checks et des convertions partout, le 100% ça ne marche que dans les labos de recherche, pas quand on a une dead line dans 15 jours).</p>
<p>Alors soyez paranos avec les codes de suppression.</p>
<p>Ce n&#8217;est pas une grosse partie du code, ça ne va pas tuer votre productivité ou plomber votre maintenance, mais contrairement aux autres snippets, vous n&#8217;aurez probablement pas de seconde chance pour le debug.</p>
<h3>C&#8217;est l&#8217;histoire d&#8217;un mec&#8230;</h3>
<p>Bon ok, de 3 mecs dans un bagnole : un matheux, un physicien et un informaticien.</p>
<p>A la sortie d&#8217;un virage, la voiture dérape et s&#8217;arrête deux roues dans le vide.</p>
<p>Les 3 compères sortent de la voiture, un peu choqués, et commencent à discuter :</p>
<p>Le mathématicien : &#8220;Il faudrait qu&#8217;on calcule la probabilité que ça nous arrive sur ce virage, avec cette voiture, dans ces conditions climatiques.&#8221;</p>
<p>Le physicien : &#8220;Il faudrait qu&#8217;on calcule le coefficient de friction et notre énergie cinétique pour mieux comprendre ce qui nous est arrivé.&#8221;</p>
<p>L&#8217;informaticien : &#8220;On reprend le virage avec la caisse pour voir si c&#8217;est reproductible ?&#8221;</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=5663&amp;md5=d5d57a21e9443ae2cd065cf3fb00f290" 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=5660
title: Appeler une fonction fabric, hors d’un fichier fabfile
uri: Appeler-une-fonction-fabric-hors-d-un-fichier-fabfile
url: http://sametmax.com/appeler-une-fonction-fabric-hors-dun-fichier-fabfile/
content:
<p>C&#8217;est con mais c&#8217;est bon à savoir : si vous avez une un tâche <a href="http://sametmax.com/travailler-moins-pour-gagner-plus-en-15-minutes-avec-python-fabric/">fabric</a>, vous pouvez tout à fait l&#8217;appeler en dehors de fabfile dans n&#8217;importe quel script Python. </p>
<p>Il suffit de faire dans ce script :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">from</span> fabric.<span style="color: black;">api</span> <span style="color: #ff7700;font-weight:bold;">import</span> run, execute, env
<span style="color: #ff7700;font-weight:bold;">from</span> fabfile <span style="color: #ff7700;font-weight:bold;">import</span> la_tache
&nbsp;
execute<span style="color: black;">&#40;</span>la_tache<span style="color: black;">&#41;</span></pre></div></div>

<p>Et on peut changer n&#8217;importe paramètre en le passant en keyword à <a href="http://docs.fabfile.org/en/1.6/api/core/tasks.html?highlight=execute#fabric.tasks.execute">execute</a>. Par exemple pour changer l&#8217;host :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">hosts = <span style="color: black;">&#91;</span><span style="color: #483d8b;">'user@serveurdistant.com'</span>, ...<span style="color: black;">&#93;</span>
execute<span style="color: black;">&#40;</span>la_tache, hosts=<span style="color: black;">&#91;</span>host<span style="color: black;">&#93;</span><span style="color: black;">&#41;</span></pre></div></div>

 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=5660&amp;md5=6f6e2c477c7748d4a1823d66d3a3fc15" 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=5670
title: Décorateur de trace
uri: Décorateur-de-trace
url: http://sametmax.com/decorateur-de-trace/
content:
<p><em>(Ceci est un post invité de <a href="http://sametmax.com/author/xonop/">xonop</a> sous licence creative common 3.0 unported.)</em></p>
<p>Suite aux superbes articles sur les <a href="http://sametmax.com/comprendre-les-decorateurs-python-pas-a-pas-partie-1">décorateurs</a> et sur l&#8217;écriture des <a href="http://sametmax.com/ecrire-des-logs-en-python/">logs en python</a> j&#8217;ai voulu mettre en pratique dans mon projet.<br />
C&#8217;est là que les ennuis ont commencé !<br />
<span id="more-5670"></span></p>
<p><strong>Objectif :</strong></p>
<p>Créer un décorateur qui me permette de tracer le passage dans certaines méthodes.<br />
Celui-ci doit :</p>
<ul>
<li>Être débrayable facilement.</li>
<li>Récupérer automatiquement le nom de la méthode, sa classe et son module.</li>
</ul>
<p><strong>Première étape : le logger</strong></p>
<p>Avant toute chose mettons en place l&#8217;environnement pour pouvoir tracer en utilisant le module logging.<br />
Pour simplifier les exemples, nous associons un seul <em>handler</em> de type <em>terminal</em>.<br />
La fonction <code>log_debug</code> permet de faire appel au logger pour tracer une information.</p>
<p><code>logger.py</code> :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> functools
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">logging</span>
&nbsp;
__DECO_ACTIVATED = <span style="color: #008000;">True</span>
__logger = <span style="color: #008000;">None</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> init_logger<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">global</span> __logger
    __logger = <span style="color: #dc143c;">logging</span>.<span style="color: black;">getLogger</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    __logger.<span style="color: black;">setLevel</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">logging</span>.<span style="color: black;">DEBUG</span><span style="color: black;">&#41;</span>
    terminalHandler = <span style="color: #dc143c;">logging</span>.<span style="color: black;">StreamHandler</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    terminalHandler.<span style="color: black;">setLevel</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">logging</span>.<span style="color: black;">DEBUG</span><span style="color: black;">&#41;</span>
    __logger.<span style="color: black;">addHandler</span><span style="color: black;">&#40;</span>terminalHandler<span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> log_debug<span style="color: black;">&#40;</span>text<span style="color: black;">&#41;</span>:
    __logger.<span style="color: black;">debug</span><span style="color: black;">&#40;</span>text<span style="color: black;">&#41;</span></pre></div></div>

<p><strong>Deuxième étape : le décorateur, version basique</strong></p>
<p>Pour commencer, le décorateur débrayable :</p>
<p><code>logger.py</code> :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> log_decorator<span style="color: black;">&#40;</span>func<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> __DECO_ACTIVATED:
        <span style="color: #ff7700;font-weight:bold;">return</span> func
&nbsp;
    @functools.<span style="color: black;">wraps</span><span style="color: black;">&#40;</span>func<span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> wrapped<span style="color: black;">&#40;</span><span style="color: #66cc66;">*</span>args, <span style="color: #66cc66;">**</span>kwargs<span style="color: black;">&#41;</span>:
        __logger.<span style="color: black;">debug</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;BEGIN&quot;</span><span style="color: black;">&#41;</span>
        data = func<span style="color: black;">&#40;</span><span style="color: #66cc66;">*</span>args, <span style="color: #66cc66;">**</span>kwargs<span style="color: black;">&#41;</span>
        __logger.<span style="color: black;">debug</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;END&quot;</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> data
    <span style="color: #ff7700;font-weight:bold;">return</span> wrapped</pre></div></div>

<p><strong>Remarques :</strong></p>
<ul>
<li>La fonction est décorée selon la valeur de la variable <code>__DECO_ACTIVATED</code>.</li>
<li>La fonction <a href="http://docs.python.org/3/library/functools.html#functools.wraps">wraps</a> du module <a href="http://docs.python.org/3/library/functools.html">functools</a> reporte les attributs de la fonction originale sur la version <em>wrappée</em> (dont les docstrings).</li>
</ul>
<p>Et maintenant un module pour tester ça :</p>
<p><code>main.py</code> :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> logger
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> Generic<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    @logger.<span style="color: black;">log_decorator</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> do_it<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, arg1<span style="color: black;">&#41;</span>:
        logger.<span style="color: black;">log_debug</span><span style="color: black;">&#40;</span>arg1<span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">if</span> __name__ == <span style="color: #483d8b;">&quot;__main__&quot;</span>:
    logger.<span style="color: black;">init_logger</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    generic = Generic<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    generic.<span style="color: black;">do_it</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;NOW&quot;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Et voilà le résultat :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">BEGIN
NOW
END</pre></div></div>

<p><strong>Troisième étape : les noms de module et de fonction</strong></p>
<p>Ces informations se récupèrent facilement, voici la nouvelle version du décorateur :</p>
<p><code>logger.py</code> :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> log_decorator<span style="color: black;">&#40;</span>func<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> __DECO_ACTIVATED:
        <span style="color: #ff7700;font-weight:bold;">return</span> func
<span style="display:block;background-color: #ffc;">    module_name = func.__module__</span><span style="display:block;background-color: #ffc;">    func_name = func.__name__</span>&nbsp;
    @functools.<span style="color: black;">wraps</span><span style="color: black;">&#40;</span>func<span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> wrapped<span style="color: black;">&#40;</span><span style="color: #66cc66;">*</span>args, <span style="color: #66cc66;">**</span>kwargs<span style="color: black;">&#41;</span>:
<span style="display:block;background-color: #ffc;">        msg = <span style="color: #483d8b;">&quot;Module={} Function={}&quot;</span>.<span style="color: black;">format</span><span style="color: black;">&#40;</span>module_name, func_name<span style="color: black;">&#41;</span></span>        __logger.<span style="color: black;">debug</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;BEGIN &quot;</span> + msg<span style="color: black;">&#41;</span>
        data = func<span style="color: black;">&#40;</span><span style="color: #66cc66;">*</span>args, <span style="color: #66cc66;">**</span>kwargs<span style="color: black;">&#41;</span>
        __logger.<span style="color: black;">debug</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;END &quot;</span> + msg<span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> data
    <span style="color: #ff7700;font-weight:bold;">return</span> wrapped</pre></div></div>

<p>Et maintenant le résultat :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">BEGIN Module=<span style="color: #dc143c;">__main__</span> Function=do_it
NOW
END Module=<span style="color: #dc143c;">__main__</span> Function=do_it</pre></div></div>

<p>Jusqu&#8217;ici tout va bien.</p>
<p><strong>Quatrième étape : le nom de la classe</strong></p>
<p>Et c&#8217;est maintenant que les choses se corsent !<br />
Tout d&#8217;abord, l&#8217;objet <code>func</code> que nous manipulons est une fonction et non une méthode de classe :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>func<span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&lt;</span>function Generic.<span style="color: black;">do_it</span> at 0x00C70348<span style="color: #66cc66;">&gt;</span></pre></div></div>

<p>En effet lors de l&#8217;exécution du décorateur, la classe en tant qu&#8217;objet n&#8217;existe pas encore.<br />
Il n&#8217;y a pas de lien direct entre la fonction et sa future classe.</p>
<p>Bon nombre de développeurs bien intentionnés nous conseillent d&#8217;utiliser <code>self</code> pour déterminer sa classe.</p>
<p><strong>Oui mais</strong> :</p>
<ul>
<li>Si la fonction n&#8217;est pas une méthode, pas de <code>self</code> !</li>
<li>La classe n&#8217;est pas obligatoirement celle de la méthode. Il peut s&#8217;agir d&#8217;une classe héritée.</li>
</ul>
<p>Pour s&#8217;en convaincre, voici le nouveau décorateur :</p>
<p><code>logger.py</code> :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> log_decorator<span style="color: black;">&#40;</span>func<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> __DECO_ACTIVATED:
        <span style="color: #ff7700;font-weight:bold;">return</span> func
    module_name = func.__module__
    func_name = func.__name__
&nbsp;
    @functools.<span style="color: black;">wraps</span><span style="color: black;">&#40;</span>func<span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> wrapped<span style="color: black;">&#40;</span><span style="color: #66cc66;">*</span>args, <span style="color: #66cc66;">**</span>kwargs<span style="color: black;">&#41;</span>:
<span style="display:block;background-color: #ffc;">        <span style="color: #ff7700;font-weight:bold;">try</span>:</span><span style="display:block;background-color: #ffc;">            class_name = args<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span>.__class__.__name__</span><span style="display:block;background-color: #ffc;">        <span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">IndexError</span>:</span><span style="display:block;background-color: #ffc;">            class_name = <span style="color: #483d8b;">&quot;&quot;</span></span><span style="display:block;background-color: #ffc;">        msg = <span style="color: #483d8b;">&quot;Module={} Class={} Function={}&quot;</span>.<span style="color: black;">format</span><span style="color: black;">&#40;</span></span><span style="display:block;background-color: #ffc;">            module_name, class_name, func_name<span style="color: black;">&#41;</span></span>        __logger.<span style="color: black;">debug</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;BEGIN &quot;</span> + msg<span style="color: black;">&#41;</span>
        data = func<span style="color: black;">&#40;</span><span style="color: #66cc66;">*</span>args, <span style="color: #66cc66;">**</span>kwargs<span style="color: black;">&#41;</span>
        __logger.<span style="color: black;">debug</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;END &quot;</span> + msg<span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> data
    <span style="color: #ff7700;font-weight:bold;">return</span> wrapped</pre></div></div>

<p>Et maintenant le module de tests :</p>
<p><code>main.py</code> :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> logger
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> Generic<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    @logger.<span style="color: black;">log_decorator</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> do_it<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, arg1<span style="color: black;">&#41;</span>:
        logger.<span style="color: black;">log_debug</span><span style="color: black;">&#40;</span>arg1<span style="color: black;">&#41;</span>
&nbsp;
<span style="display:block;background-color: #ffc;"><span style="color: #ff7700;font-weight:bold;">class</span> Specific<span style="color: black;">&#40;</span>Generic<span style="color: black;">&#41;</span>:</span><span style="display:block;background-color: #ffc;">    @logger.<span style="color: black;">log_decorator</span></span><span style="display:block;background-color: #ffc;">    <span style="color: #ff7700;font-weight:bold;">def</span> do_it<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, arg1<span style="color: black;">&#41;</span>:</span><span style="display:block;background-color: #ffc;">        <span style="color: #008000;">super</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>.<span style="color: black;">do_it</span><span style="color: black;">&#40;</span>arg1<span style="color: black;">&#41;</span></span>&nbsp;
<span style="color: #ff7700;font-weight:bold;">if</span> __name__ == <span style="color: #483d8b;">&quot;__main__&quot;</span>:
    logger.<span style="color: black;">init_logger</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="display:block;background-color: #ffc;">    specific = Specific<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></span><span style="display:block;background-color: #ffc;">    specific.<span style="color: black;">do_it</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;NOW&quot;</span><span style="color: black;">&#41;</span></span></pre></div></div>

<p>Et le résultat tant attendu :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">BEGIN Module=<span style="color: #dc143c;">__main__</span> Class=Specific Function=do_it
BEGIN Module=<span style="color: #dc143c;">__main__</span> Class=Specific Function=do_it
NOW
END Module=<span style="color: #dc143c;">__main__</span> Class=Specific Function=do_it
END Module=<span style="color: #dc143c;">__main__</span> Class=Specific Function=do_it</pre></div></div>

<p>Et là c&#8217;est le drâme, on a perdu la classe <code>Generic</code> ! Mais analysons plutôt l&#8217;exécution :</p>
<ul>
<li>Appel de la méthode <code>Specific.do_it()</code> vu que l&#8217;objet <code>generic</code> est une instance de cette classe.</li>
<li>Appel de la méthode <code>Generic.do_it()</code> par le biais de l&#8217;instruction <code>super().do_it()</code></li>
</ul>
<p>Comme prévu, la classe de l&#8217;objet <code>self</code> ne change pas que l&#8217;on soit dans une méthode de la classe ou de l&#8217;une de ses super-classes.</p>
<p><strong>Quatrième étape : autre approche</strong></p>
<p>Ne pouvant déterminer directement la classe d&#8217;appartenance de la fonction, essayons de la chercher dans le module.<br />
Pour commencer il nous faut l&#8217;objet <code>module</code> alors que nous ne connaissons que son nom.<br />
Le module <a href="http://docs.python.org/3/library/inspect.html">inspect</a> propose justement ce service grâce à <a href="http://docs.python.org/3/library/inspect.html#inspect.getmodule">getmodule</a>.<br />
Voici le décorateur modifié :</p>
<p><code>logger.py</code> :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">inspect</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> log_decorator<span style="color: black;">&#40;</span>func<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> __DECO_ACTIVATED:
        <span style="color: #ff7700;font-weight:bold;">return</span> func
    module_name = func.__module__
<span style="display:block;background-color: #ffc;">    module_obj = <span style="color: #dc143c;">inspect</span>.<span style="color: black;">getmodule</span><span style="color: black;">&#40;</span>func<span style="color: black;">&#41;</span></span><span style="display:block;background-color: #ffc;">    class_name = <span style="color: #483d8b;">&quot;UNKNOWN&quot;</span></span><span style="display:block;background-color: #ffc;">    <span style="color: #ff7700;font-weight:bold;">for</span> key, obj <span style="color: #ff7700;font-weight:bold;">in</span> module_obj.<span style="color: #0000cd;">__dict__</span>.<span style="color: black;">items</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:</span><span style="display:block;background-color: #ffc;">        <span style="color: #ff7700;font-weight:bold;">try</span>:</span><span style="display:block;background-color: #ffc;">            members = obj.<span style="color: #0000cd;">__dict__</span></span><span style="display:block;background-color: #ffc;">            method = members<span style="color: black;">&#91;</span>func.__name__<span style="color: black;">&#93;</span></span><span style="display:block;background-color: #ffc;">            <span style="color: #ff7700;font-weight:bold;">if</span> method == func:</span><span style="display:block;background-color: #ffc;">                class_name = key</span><span style="display:block;background-color: #ffc;">                <span style="color: #ff7700;font-weight:bold;">break</span></span><span style="display:block;background-color: #ffc;">        <span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: black;">&#40;</span><span style="color: #008000;">KeyError</span>, <span style="color: #008000;">AttributeError</span><span style="color: black;">&#41;</span>:</span><span style="display:block;background-color: #ffc;">            <span style="color: #ff7700;font-weight:bold;">pass</span></span>    func_name = func.__name__
&nbsp;
    @functools.<span style="color: black;">wraps</span><span style="color: black;">&#40;</span>func<span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> wrapped<span style="color: black;">&#40;</span><span style="color: #66cc66;">*</span>args, <span style="color: #66cc66;">**</span>kwargs<span style="color: black;">&#41;</span>:
        msg = <span style="color: #483d8b;">&quot;Module={} Class={} Function={}&quot;</span>.<span style="color: black;">format</span><span style="color: black;">&#40;</span>
            module_name, class_name, func_name<span style="color: black;">&#41;</span>
        __logger.<span style="color: black;">debug</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;BEGIN &quot;</span> + msg<span style="color: black;">&#41;</span>
        data = func<span style="color: black;">&#40;</span><span style="color: #66cc66;">*</span>args, <span style="color: #66cc66;">**</span>kwargs<span style="color: black;">&#41;</span>
        __logger.<span style="color: black;">debug</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;END &quot;</span> + msg<span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> data
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">return</span> wrapped</pre></div></div>

<p>Pour rechercher la fonction, le décorateur doit :</p>
<ul>
<li>Lister les objets du module.</li>
<li>Rechercher pour chaque objet le nom de la fonction dans les attributs de celui-ci. Si l&#8217;attribut correspond à notre fonction, c&#8217;est gagné !</li>
</ul>
<p>Nous obtenons alors :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">BEGIN Module=<span style="color: #dc143c;">__main__</span> Class=UNKNOWN Function=do_it
BEGIN Module=<span style="color: #dc143c;">__main__</span> Class=UNKNOWN Function=do_it
NOW
END Module=<span style="color: #dc143c;">__main__</span> Class=UNKNOWN Function=do_it
END Module=<span style="color: #dc143c;">__main__</span> Class=UNKNOWN Function=do_it</pre></div></div>

<p>Pas glop ça marche pas !<br />
Regardons le contenu du module avant la recherche :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>module_obj.<span style="color: #0000cd;">__dict__</span>.<span style="color: black;">keys</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
dict_keys<span style="color: black;">&#40;</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">'__builtins__'</span>, <span style="color: #483d8b;">'__name__'</span>, <span style="color: #483d8b;">'__file__'</span>, <span style="color: #483d8b;">'__doc__'</span>, <span style="color: #483d8b;">'__loader__'</span>,
           <span style="color: #483d8b;">'__cached__'</span>, <span style="color: #483d8b;">'logger'</span>, <span style="color: #483d8b;">'__package__'</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Curieusement les classes n&#8217;apparaissent pas, mais c&#8217;est tout à fait normal.<br />
Comme vu précédemment, lors de l&#8217;exécution du décorateur la classe est en instance de création.<br />
Il faut donc faire cette recherche lors de l&#8217;exécution de la fonction <em>wrappée</em>.</p>
<p>Le décorateur devient donc :</p>
<p><code>logger.py</code> :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> log_decorator<span style="color: black;">&#40;</span>func<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> __DECO_ACTIVATED:
        <span style="color: #ff7700;font-weight:bold;">return</span> func
    module_name = func.__module__
    module_obj = <span style="color: #dc143c;">inspect</span>.<span style="color: black;">getmodule</span><span style="color: black;">&#40;</span>func<span style="color: black;">&#41;</span>
    func_name = func.__name__
&nbsp;
    @functools.<span style="color: black;">wraps</span><span style="color: black;">&#40;</span>func<span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> wrapped<span style="color: black;">&#40;</span><span style="color: #66cc66;">*</span>args, <span style="color: #66cc66;">**</span>kwargs<span style="color: black;">&#41;</span>:
<span style="display:block;background-color: #ffc;">        class_name = <span style="color: #483d8b;">&quot;UNKNOWN&quot;</span></span><span style="display:block;background-color: #ffc;">        <span style="color: #ff7700;font-weight:bold;">for</span> key, obj <span style="color: #ff7700;font-weight:bold;">in</span> module_obj.<span style="color: #0000cd;">__dict__</span>.<span style="color: black;">items</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:</span><span style="display:block;background-color: #ffc;">            <span style="color: #ff7700;font-weight:bold;">try</span>:</span><span style="display:block;background-color: #ffc;">                members = obj.<span style="color: #0000cd;">__dict__</span></span><span style="display:block;background-color: #ffc;">                method = members<span style="color: black;">&#91;</span>func.__name__<span style="color: black;">&#93;</span></span><span style="display:block;background-color: #ffc;">                <span style="color: #ff7700;font-weight:bold;">if</span> method == func:</span><span style="display:block;background-color: #ffc;">                    class_name = key</span><span style="display:block;background-color: #ffc;">                    <span style="color: #ff7700;font-weight:bold;">break</span></span><span style="display:block;background-color: #ffc;">            <span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: black;">&#40;</span><span style="color: #008000;">KeyError</span>, <span style="color: #008000;">AttributeError</span><span style="color: black;">&#41;</span>:</span><span style="display:block;background-color: #ffc;">                <span style="color: #ff7700;font-weight:bold;">pass</span></span><span style="display:block;background-color: #ffc;">        msg = <span style="color: #483d8b;">&quot;Module={} Class={} Function={}&quot;</span>.<span style="color: black;">format</span><span style="color: black;">&#40;</span></span><span style="display:block;background-color: #ffc;">            module_name, class_name, func_name<span style="color: black;">&#41;</span></span>        __logger.<span style="color: black;">debug</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;BEGIN &quot;</span> + msg<span style="color: black;">&#41;</span>
        data = func<span style="color: black;">&#40;</span><span style="color: #66cc66;">*</span>args, <span style="color: #66cc66;">**</span>kwargs<span style="color: black;">&#41;</span>
        __logger.<span style="color: black;">debug</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;END &quot;</span> + msg<span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> data
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">return</span> wrapped</pre></div></div>

<p>Et le résultat :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">BEGIN Module=<span style="color: #dc143c;">__main__</span> Class=UNKNOWN Function=do_it
BEGIN Module=<span style="color: #dc143c;">__main__</span> Class=UNKNOWN Function=do_it
NOW
END Module=<span style="color: #dc143c;">__main__</span> Class=UNKNOWN Function=do_it
END Module=<span style="color: #dc143c;">__main__</span> Class=UNKNOWN Function=do_it</pre></div></div>

<p>Pas glop 2 le retour !<br />
Faisons appel au débogueur suprême : <code>print</code></p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">key    = Generic
method = <span style="color: #66cc66;">&lt;</span>function Generic.<span style="color: black;">do_it</span> at 0x00D07C90<span style="color: #66cc66;">&gt;</span>
func   = <span style="color: #66cc66;">&lt;</span>function Specific.<span style="color: black;">do_it</span> at 0x00D07CD8<span style="color: #66cc66;">&gt;</span>
&nbsp;
key    = Specific
method = <span style="color: #66cc66;">&lt;</span>function Specific.<span style="color: black;">do_it</span> at 0x00D07D20<span style="color: #66cc66;">&gt;</span>
func   = <span style="color: #66cc66;">&lt;</span>function Specific.<span style="color: black;">do_it</span> at 0x00D07CD8<span style="color: #66cc66;">&gt;</span></pre></div></div>

<p>Effectivement les références ne correspondent pas, et encore une fois, rien de plus normal.<br />
La fonction d&#8217;origine a été <em>wrappée</em> donc celle présente dans le module n&#8217;est plus celle d&#8217;origine.<br />
Qu&#8217;à cela ne tienne, recherchons-là !</p>
<p>Après la déclaration de la fonction <code>wrapped</code>, le décorateur la mémorise dans la variable <code>wrapped_function</code>.<br />
Elle sera utilisée à l&#8217;exécution de la fonction.</p>
<p><code>logger.py</code> :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> log_decorator<span style="color: black;">&#40;</span>func<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> __DECO_ACTIVATED:
        <span style="color: #ff7700;font-weight:bold;">return</span> func
    module_name = func.__module__
    module_obj = <span style="color: #dc143c;">inspect</span>.<span style="color: black;">getmodule</span><span style="color: black;">&#40;</span>func<span style="color: black;">&#41;</span>
    func_name = func.__name__
&nbsp;
    @functools.<span style="color: black;">wraps</span><span style="color: black;">&#40;</span>func<span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> wrapped<span style="color: black;">&#40;</span><span style="color: #66cc66;">*</span>args, <span style="color: #66cc66;">**</span>kwargs<span style="color: black;">&#41;</span>:
        class_name = <span style="color: #483d8b;">&quot;UNKNOWN&quot;</span>
        <span style="color: #ff7700;font-weight:bold;">for</span> key, obj <span style="color: #ff7700;font-weight:bold;">in</span> module_obj.<span style="color: #0000cd;">__dict__</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;">try</span>:
                members = obj.<span style="color: #0000cd;">__dict__</span>
                method = members<span style="color: black;">&#91;</span>func.__name__<span style="color: black;">&#93;</span>
<span style="display:block;background-color: #ffc;">                <span style="color: #ff7700;font-weight:bold;">if</span> method == wrapped_function:</span>                    class_name = key
                    <span style="color: #ff7700;font-weight:bold;">break</span>
            <span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: black;">&#40;</span><span style="color: #008000;">KeyError</span>, <span style="color: #008000;">AttributeError</span><span style="color: black;">&#41;</span>:
                <span style="color: #ff7700;font-weight:bold;">pass</span>
        msg = <span style="color: #483d8b;">&quot;Module={} Class={} Function={}&quot;</span>.<span style="color: black;">format</span><span style="color: black;">&#40;</span>
            module_name, class_name, func_name<span style="color: black;">&#41;</span>
        __logger.<span style="color: black;">debug</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;BEGIN &quot;</span> + msg<span style="color: black;">&#41;</span>
        data = func<span style="color: black;">&#40;</span><span style="color: #66cc66;">*</span>args, <span style="color: #66cc66;">**</span>kwargs<span style="color: black;">&#41;</span>
        __logger.<span style="color: black;">debug</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;END &quot;</span> + msg<span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> data
&nbsp;
<span style="display:block;background-color: #ffc;">    wrapped_function = wrapped</span>    <span style="color: #ff7700;font-weight:bold;">return</span> wrapped</pre></div></div>

<p>Et maintenant le résultat :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">BEGIN Module=<span style="color: #dc143c;">__main__</span> Class=Specific Function=do_it
BEGIN Module=<span style="color: #dc143c;">__main__</span> Class=Generic Function=do_it
NOW
END Module=<span style="color: #dc143c;">__main__</span> Class=Generic Function=do_it
END Module=<span style="color: #dc143c;">__main__</span> Class=Specific Function=do_it</pre></div></div>

<p>Ouf ! Ca marche !</p>
<p>Au menu du prochain épisode : logger la valeur de certains paramètres passés à la fonction décorée.</p>
<p><em>Xavier O. avec l&#8217;aide précieuse de Laurent B.</em></p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=5670&amp;md5=ed725fc730fad3935f341c888770c289" 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=5784
title: Hic
uri: Hic
url: http://sametmax.com/hic/
content:
<p>Bon, il est 1 h du mat, et je suis bourré.</p>
<p>N&#8217;ayant pas pondu l&#8217;article quotidien, j&#8217;ai tenté une approche artisanale en rentrant du bar pour taper un truc vite fait mais j&#8217;ai l&#8217;impression d&#8217;avoir un clavier en VREFTY.</p>
<p>Bref, je crois qu&#8217;il vaut mieux que je tape rien plutôt que de la merde.</p>
<p>Et je me dis qu&#8217;il vaut mieux ne rien publier que cet article inutile, mais en même temps ça fait 20 minutes que j&#8217;essaye de le taper, alors maintenant qu&#8217;il est là, j&#8217;ai pas envie de le jetter.</p>
<p>Pardon aux familles, tout ça.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=5784&amp;md5=59614f5822df7d7ee6ff7bcd303bff0f" 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=5508
title: Utilisez des variables globales avec JSLint
uri: Utilisez-des-variables-globales-avec-JSLint
url: http://sametmax.com/utilisez-des-variables-globales-avec-jslint/
content:
<p>Petite astuce si vous utilisez <a href="http://www.jslint.com/">JSlint </a>(par exemple via le <a href="https://github.com/SublimeLinter/SublimeLinter">super plugin Sublime Text</a>).</p>
<p>Il va vous mettre en avant toutes les variables globales ou non déclarées précédement. C&#8217;est génial la plupart du temps, mais c&#8217;est un peu chiant pour des variables qui sont volontairement globales et mises à dispo par d&#8217;autres scripts comme les frameworks et libs.</p>
<p>Par exemple, il va vous déclarer que jQuery est une variable globale ou non déclarée. Pour éviter ça, mettez ce commentaire tout en haut du fichier :</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #006600; font-style: italic;">/*global jQuery:true, $:true */</span></pre></div></div>

<p>JSLint va le prendre en compte et ignorer ces variables.</p>
<p>On peut lister autant de variables qu&#8217;on le souhaite.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=5508&amp;md5=1be789a49c4be721cd7ce043a975c1b9" 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=5793
title: Lire et écrire dans un fichier XLS avec Python
uri: Lire-et-écrire-dans-un-fichier-XLS-avec-Python
url: http://sametmax.com/lire-et-ecrire-dans-un-fichier-xls/
content:
<p>< Insérer ici vous-même troll sur Microsoft et LibreOffice et les formats ></p>
<p>Puis, une fois cette corvée administrative remplie, faites un <a href="http://sametmax.com/votre-python-aime-les-pip/">pip install</a>:</p>

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

<p>Ceci va installer deux lib dont on va avoir besoin : <a href="https://pypi.python.org/pypi/xlrd">xlrd</a> pour la lecture, et <a href="https://pypi.python.org/pypi/xlwt">xlwt</a> pour l&#8217;écriture.</p>
<p>Ensuite c&#8217;est très simple&#8230;</p>
<p>Pour écrire dans un fichier Excel :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> xlrd
&nbsp;
<span style="color: #ff7700;font-weight:bold;">from</span> xlwt <span style="color: #ff7700;font-weight:bold;">import</span> Workbook, Formula
&nbsp;
path = r<span style="color: #483d8b;">&quot;C:<span style="color: #000099; font-weight: bold;">\c</span>hemin<span style="color: #000099; font-weight: bold;">\v</span>ers<span style="color: #000099; font-weight: bold;">\f</span>ichier.xls&quot;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># On créer un &quot;classeur&quot;</span>
classeur = Workbook<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #808080; font-style: italic;"># On ajoute une feuille au classeur</span>
feuille = classeur.<span style="color: black;">add_sheet</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;OCB&quot;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Ecrire &quot;1&quot; dans la cellule à la ligne 0 et la colonne 0</span>
feuille.<span style="color: black;">write</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span>, <span style="color: #ff4500;">0</span>, <span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>
<span style="color: #808080; font-style: italic;"># Ecrire &quot;2&quot; dans la cellule à la ligne 0 et la colonne 1</span>
feuille.<span style="color: black;">write</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span>, <span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span>
<span style="color: #808080; font-style: italic;"># Ecrire une formule dans la cellule à la ligne 0 et la colonne 2</span>
<span style="color: #808080; font-style: italic;"># qui va additioner les deux autres cellules</span>
feuille.<span style="color: black;">write</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span>, <span style="color: #ff4500;">2</span>, Formula<span style="color: black;">&#40;</span><span style="color: #483d8b;">'A1+B1'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Ecriture du classeur sur le disque</span>
classeur.<span style="color: black;">save</span><span style="color: black;">&#40;</span>path<span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">print</span> u<span style="color: #483d8b;">&quot;Fichier créé: {}&quot;</span>.<span style="color: black;">format</span><span style="color: black;">&#40;</span>path<span style="color: black;">&#41;</span>
<span style="color: #808080; font-style: italic;">## Fichier créé: C:\chemin\vers\fichier.xls</span>
&nbsp;
workbook.<span style="color: black;">save</span><span style="color: black;">&#40;</span>path<span style="color: black;">&#41;</span></pre></div></div>

<p>Ce qui nous pond un truc comme <a href="https://github.com/sametmax/codes-des-articles/raw/master/2013/avril/fichier.xls">ça</a>.</p>
<p>Et pour lire ce même fichier :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> xlrd
&nbsp;
<span style="color: #808080; font-style: italic;"># Réouverture du classeur</span>
classeur = xlrd.<span style="color: black;">open_workbook</span><span style="color: black;">&#40;</span>path<span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Récupération du nom de toutes les feuilles sous forme de liste</span>
nom_des_feuilles = classeur.<span style="color: black;">sheet_names</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Récupération de la première feuille</span>
feuille = classeur.<span style="color: black;">sheet_by_name</span><span style="color: black;">&#40;</span>nom_des_feuilles<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">print</span> u<span style="color: #483d8b;">&quot;Lecture des cellules:&quot;</span>
<span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">&quot;A1: {}&quot;</span>.<span style="color: black;">format</span><span style="color: black;">&#40;</span>feuille.<span style="color: black;">cell_value</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span>, <span style="color: #ff4500;">0</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: #483d8b;">&quot;B1: {}&quot;</span>.<span style="color: black;">format</span><span style="color: black;">&#40;</span>feuille.<span style="color: black;">cell_value</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span>, <span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #808080; font-style: italic;"># On ne peut pas lire les les valeurs des cellules avec formules</span>
<span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">&quot;C1: {}&quot;</span>.<span style="color: black;">format</span><span style="color: black;">&#40;</span>feuille.<span style="color: black;">cell_value</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span>, <span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #808080; font-style: italic;">## Lecture des cellules:</span>
<span style="color: #808080; font-style: italic;">## A1: 1.0</span>
<span style="color: #808080; font-style: italic;">## B1: 2.0</span>
<span style="color: #808080; font-style: italic;">## C1:</span></pre></div></div>

<p>Comme vous pouvez le voir à la dernière ligne, lire une cellule avec une formule ne revoit rien. L&#8217;auteur de la lib <a href="http://stackoverflow.com/a/4695498/9951">explique</a> en effet que les formules sont stockées sous forme de bytecode et qu&#8217;il faudrait les décompiler pour obtenir le texte original.</p>
<p>Il existe d&#8217;autres manières d&#8217;accéder à des fichiers XLS, puis puissantes mais aussi beaucoup plus contraignantes : </p>
<ul>
<li><a href="http://www.blog.pythonlibrary.org/2010/07/16/python-and-microsoft-office-using-pywin32/">Manipuler Office directement via l&#8217;API COM</a>: Windows uniquement, et nécessite d&#8217;avoir le logiciel installé.</li>
<li><a href="http://wiki.openoffice.org/wiki/Using_Python_on_Windows">Manipuler Open Office via l&#8217;API UNO</a>, qui demande aussi d&#8217;avoir la suite bureautique installée.</li>
</ul>
<hr />
<p><a href="https://github.com/sametmax/codes-des-articles/blob/master/2013/avril/excel.py">Télécharger le code de l&#8217;article</a></p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=5793&amp;md5=52fa01172d671122eb789866498c3c1b" 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=5814
title: Dans la peau d’un formateur
uri: Dans-la-peau-d-un-formateur
url: http://sametmax.com/dans-la-peau-dun-formateur/
content:
<p>J&#8217;ai contacté un a un des organismes de formation pour me signaler comme disponible en tant que formateur Python/Django, HTML, CSS, Javascript et Git. Certains ne vérifient rien, d&#8217;autres me demandent un plan de cours, voir un support et un CV.</p>
<p>Des semaines voir des mois plus tard, un email arrive. On me demande si je suis disponible pour une session, généralement entre 2 et 5 jours, avec une grande majorité de 3.</p>
<p>Le commercial me communique peu d&#8217;informations : leur plan de cours vendu, les dates (potentielles) et le nombre (encore potentiel) de participants, et me demande un devis à la journée.</p>
<p>À ce stade, je check mon agenda pour vérifier ma disponibilité, et je regarde si ça peut être rentable : certaines missions sont loin et chaque jour séparé à bonne distance du suivant, d&#8217;autres sont facilement accessibles et groupées d&#8217;une traite. Malgré votre expertise et vos aspirations éducatives, le temps et l&#8217;espace ont toujours droit de veto sur vos choix de vie.</p>
<p>Il vous faut alors répondre rapidement, mais surtout fournir une estimation de la facturation qui oscille entre 500-800 €/j selon la difficulté du sujet traité, le nombre de participants, les conditions de travail proposée et les frais que je pense rencontrer.</p>
<p>Concernant la difficulté du sujet traité, l&#8217;écrasante majorité des formations sont pour débutants, au moins dans la technologie ciblée. Rarement on vous demandera de couvrir des design patterns avancés, de l&#8217;analyse de données biologiques ou autre. </p>
<p>Le nombre de participants, lui, excède en peu d&#8217;occasions 5, et c&#8217;est une bonne chose. Au delà, il est difficile de faire plus que du cours magistral, et c&#8217;est en faisant ce constat que j&#8217;ai fais la paix avec les plus mauvais enseignants de mon enfance. C&#8217;est un boulot qui demande une énergie de fou si on veut le faire bien.</p>
<p>Quand aux conditions de travail, il y a ce qu&#8217;on appelle les &#8220;intra&#8221;, qui se font chez le client, et les &#8220;inter&#8221;, qui se font dans le centre de formation, mais avec des apprenants venus de différentes boîtes. Entre en jeu des tas de paramètres : si vous allez faire votre show dans une usine de traitement des déchets à Orléan, ce n&#8217;est pas la même que dans une salle climatisée avec des machines neuves à Belleville. À l&#8217;inverse, former deux collègues qui se connaissent depuis 20 ans, c&#8217;est bien plus facile que d&#8217;intéresser un codeur Pascal  proche de la retraite, un stagiaire de boîte de com et un consultant de SS2I qui se sont d&#8217;entrée installés à deux chaise d&#8217;écart les uns des autres.</p>
<p>Malheureusement, vous aurez rarement tous ces détails à l&#8217;avance, et pas de bon de commande sans devis. Vous lancez WOW, vous faites un random 100, et vous priez. </p>
<p>Plus on connaît l&#8217;organisme, plus on a des infos précises, nombreuses et rapidement. Ça devient donc plus facile avec le temps, et c&#8217;est une des nombreuses raisons pour lesquelles vous devez entretenir de très bonnes relations avec vos organismes de formation.</p>
<p>Ces derniers sont de toutes sortes : grands, corporates, petits, artisanaux, généralistes, spécialisés, automatisé, manuels, etc. Il n&#8217;y a qu&#8217;une seule chose importante pour vous : la relation que vous avez avec eux. Personnellement je préfère couper les ponts avec ceux avec lesquels ce n&#8217;est pas parfait et ne garder que ceux avec lesquels ça coule tout seul. Je ne pourrai pas vous lister ceux avec lesquels j&#8217;ai des contacts car l&#8217;anonymat de ce blog est plus que fébrile.</p>
<p>Un bon indicateur est le temps de réponse par email et l&#8217;accessibilité de leurs commerciaux. Si vous pouvez avoir leur numéro de portable facilement, c&#8217;est souvent positif pour la suite. Car de la réactivité s&#8217;extrapole la propreté de l&#8217;organisation, l&#8217;état des salles de cours et la qualité de votre traitement en général.</p>
<p>Arrive l&#8217;attente et l&#8217;incertitude : 9 formations sur 10 sont annulées, parfois à la dernière minute, pour des raisons diverses. Il faut dire qu&#8217;entre le moment où quelqu&#8217;un fait sa demande et votre intervention, le dossier passe plusieurs fois par la hiérarchie, les RH et la compta. Quelques organismes de formations sont mis en concurrence, qui eux-même mettent en concurrence les formateurs. Ajoutez à ceci qu&#8217;il faut que tous les planning concordent et, dans le cadre du DIF, que la demande soit validée par l&#8217;état. Ça fait beaucoup de si.</p>
<p>Vous, vous avez bloqué cette période. Si vous êtes salariés, vous avez pris des vacances. Si vous êtes freelance, vous avez refusé des clients. Et ceci gonfle le prix de vos prestations.</p>
<p>Coup de chance, celle-ci est acceptée. Il y aura un participant de moins, mais juste assez pour être rentable pour mon intermédiaire. Il me l&#8217;annoncera généralement 2 semaines à l&#8217;avance, mais c&#8217;est déjà arrivé que la nouvelle tombe 5 jours avant l&#8217;heure H, avec un déplacement de 800 bornes prévu.</p>
<p>C&#8217;est là que je demande à avoir le numéro de téléphone ou l&#8217;email des participants, de telle sorte que je puisse connaître des choses essentielles comme : </p>
<ul>
<li>Le cœur de métier de leurs entreprises, la mission de leurs départements et leurs rôles dans tous ça.</li>
<li>Leur expérience dans la technologie qui va être enseignée. Il faut demander un exemple concret de réalisation qui a été utilisé par quelqu&#8217;un d&#8217;autres que l&#8217;auteur pour avoir une bonne idée de la chose.</li>
<li>Leur expérience dans des technologies similaires. Si je fais une formation Python, je demande quels autres langages ils connaissent, ceux qu&#8217;ils maîtrisent le mieux, ceux qu&#8217;ils préfèrent, etc. Les analogies sont les meilleurs des raccourcis pédagogiques.</li>
<li>Leur environnement de travail (OS, IDE, libs&#8230;)</li>
<li>Ce qu&#8217;ils comptent faire avec leur nouveau talent une fois rentré à la base.</li>
</ul>
<p>Il ne faut pas non plus oublier de récupérer les informations suivante auprès de  l&#8217;organisme de formation, afin d&#8217;éviter les mauvaises surprises:</p>
<ul>
<li>La présence d&#8217;une connexion internet sur le lieu de formation.</li>
<li>Les noms et versions des logiciels que l&#8217;on va utiliser (OS, langage, IDE, etc)</li>
<li>L&#8217;état de l&#8217;environnement (lib installées, outils installés, a-t-on les droits admin)</li>
<li>L&#8217;adresse et l&#8217;heure de chaque session.</li>
<li>Le nombre définitif de participants (posez la question deux fois, pour être sûr)</li>
<li>La présence d&#8217;un des membres de l&#8217;équipe de l&#8217;organisme durant toute ou partie de la formation.</li>
</ul>
<p>J&#8217;ai rarement la chance d&#8217;avoir un accès direct aux participants, mais transmettre un questionnaire à ces derniers ou au moins leur responsable de formation ne pose pas de problème. Le retour n&#8217;est pas complet, mais c&#8217;est mieux que rien.</p>
<p>Étape suivante : envoie du support de cours à l&#8217;organisme pour impression. On est informaticiens, mais les gens adorent toujours le papier. Il n&#8217;est pas rare que je vois des cahiers petits carreaux scribouillés frénétiquement pendant les sessions. J&#8217;envoie systématiquement un support de cours générique pour deux raisons :</p>
<ul>
<li>L&#8217;organisme de formation ne le conteste pas. Good enougth pour lui, et sa crédibilité. Moins de travail pour moi.</li>
<li>Je ne l&#8217;utilise jamais. Je met le plan de cours officiel à la poubelle dès la première minute du cours.</li>
</ul>
<p>Quand la formation commence, les premières heures sont déterminantes. D&#8217;abord, je dois asseoir ma crédibilité en temps qu&#8217;expert, et comme je suis très jeune et que j&#8217;ai pas la gueule de geek des séries télés, les vieux routards ont des doutes. L&#8217;astuce consiste à tout de suite parler de leurs technos, sur laquelle j&#8217;ai fais une veille avant, afin que la conversation crée une complicité tout en les rassurant sur mes compétences. </p>
<p>Les présentation doivent être chaleureuses, mais pas de blagues pendant la première demi-heure, après on peut se détendre. Le deuxième jour on peut prendre l&#8217;apéro.</p>
<p>Comme je l&#8217;écrivais plus haut, j&#8217;annonce cash aux élèves que je ne vais pas suivre le plan de cours, que j&#8217;ai adapté une formation spécialement faite pour eux et que je la modifierai à la volée pour coller à leurs attentes. Je peux faire cela car je suis non seulement un développeur compétent, mais aussi et surtout un bon formateur : je peux improviser des cours complets de tête avec aisance.</p>
<p>Ma spécialité est donc de faire du sur mesure, alors qu&#8217;on leur à vendu du thon en boîte.</p>
<p>Pas de slides, dans mes cours, on pratique. Je ne sors pas du code de ma poche, je le tape en direct devant eux, afin qu&#8217;ils voient la démarche. Je rajoute toujours des astuces pour aller plus loin, mais sans les détailler, afin qu&#8217;ils aient des choses en tête en retournant chez eux. Je fais des blagues, bien entendu. Et parfois je tire sur eux avec un pistolet à fléchettes.</p>
<p>Je ne reste jamais statique très longtemps. La chaise me sert à rentrer le code, ensuite je me lève. Je passe derrière eux alors que je parle, pour les obliger à me suivre. Je fais des emphases, je change de rythme, j&#8217;improvise des exercices sur l&#8217;actualité, des thèmes controversés (calculer le bénéfice d&#8217;une cargaison de hash, télécharger des images de youporn&#8230;) ou en rapport avec leurs projets en cours.</p>
<p>J&#8217;essaye de les faire sortir de la matière. Je parle de Dukto, de Sublime Text, d&#8217;OS alternatifs, de méthodes agiles&#8230; Pas longtemps, juste assez pour casser la monotonie, et apporter un plus. Si un débat se lève, je taquine un peu, puis recentre sur le sujet en demandant à reporter la discussion au déjeuner, que l&#8217;on passe tous ensemble. Parfois, je paie la tournée.</p>
<p>À la fin, je donne mon numéro de téléphone et mon email personnels en invitant les participant à me contacter en cas de coup dur, bien que la plupart des organismes de formation n&#8217;aiment pas vraiment cette idée.</p>
<p>Quand je rentre le soir après chaque cours, je m&#8217;écroule sur le lit tout habillé, et je dors.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=5814&amp;md5=890b882a6492787ea5fcd8573c4a0c6e" 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=5819
title: Deux conneries à la seconde
uri: Deux-conneries-à-la-seconde
url: http://sametmax.com/deux-conneries-a-la-seconde/
content:
<p>Je ne sais plus si je l&#8217;ai raconté sur le blog, mais quand j&#8217;étais gosse, j&#8217;avais lu un dessin de Reiser (ou Plantu, je ne sais plus bien) qui m&#8217;avait marqué. Je ne l&#8217;ai jamais retrouvé.</p>
<p>Il y avait un dialogue entre deux personnages :</p>
<p>- «les ordinateurs sont formidables», disait le premier. «Il peuvent calculer 20 milliards d&#8217;opérations à la seconde, avec seulement une erreur toutes les 10 milliards d&#8217;opérations »<br />
- L&#8217;autre répond : «2 conneries à la seconde, t&#8217;appelles ça un progrès ?»</p>
<p>Internet est un réseau de millions d&#8217;ordinateurs aux ordres de millions de consciences humaines.</p>
<p>Si il y a une définition de ce qu&#8217;est un catalyseur, Internet est l&#8217;exemple qui la suit dans le dictionnaire.</p>
<p>Comme tous les catalyseurs, Internet est neutre, il permet de faire plus vite, plus efficacement et à plus large échelle tout ce dont l&#8217;humanité est capable. Les hommes consomment plus vite, apprennent plus vite, lisent plus vite, s&#8217;informent plus vite, produisent plus vite, communiquent plus vite, créent plus vite, publient plus vite, débattent plus vite, prennent des décisions plus vite, jouent plus vite, échangent plus vite&#8230;</p>
<p>Et avec plus de personnes. A moindre coût.</p>
<h2>Effets secondaires</h2>
<p>Comme l&#8217;humanité n&#8217;est pas parfaite, le catalyseur démultiplie aussi ce que l&#8217;humanité fait de pire : les terroristes s&#8217;organisent plus vite, les pédophiles se satisfont plus vite, les dealers vendent plus vite, les extrêmes idéologiques prennent des forces plus vite&#8230;</p>
<p>Tout comme le couteau permet de travailler plus vite et, entre autre, de tuer plus vite.</p>
<p>Tout comme l&#8217;imprimerie permet de transmettre le savoir plus vite, y compris celui de faire des bombes.</p>
<p>Tout comme la voiture permet de déplacer plus vite, y compris la cocaïne.</p>
<p>C&#8217;est vrai, il y avait moins de Go Fast en 1935.</p>
<p>Aujourd&#8217;hui on veut vous faire croire que parce que l’ordinateur permet de faire deux conneries à la seconde, il faut tout protéger. Tout verrouiller. Tout vérifier.</p>
<p>Parce qu&#8217;Internet donne une puissance énorme aux malades sexuels, aux fanas des explosifs et aux porteurs d&#8217;idées noires, il faut légiférer, espionner, contrôler et brider.</p>
<p>Mais la somme de l&#8217;humanité, c&#8217;est plus que la souffrance des enfants maltraités par des pervers. C&#8217;est le potentiel, pour des des millions d&#8217;enfants, d&#8217;avoir accès à n&#8217;importe quelle information pour pallier à l&#8217;imperfection de l&#8217;éducation locale.</p>
<p>La somme de l&#8217;humanité, c&#8217;est plus que la violence de xénophobes agressifs qui instillent la haine. C&#8217;est le potentiel de millions de citoyens qui savent, et peuvent, plus et mieux, défendre l&#8217;avenir de leurs sociétés.</p>
<p>La somme de l&#8217;humanité, c&#8217;est plus que la mort sanglante des victimes des bombes du marathon. C&#8217;est le potentiel des millions de personnes qui vivent dans des pays éloignés par la distance et la culture, mais qui peuvent entrer en contact, et apprendre à s&#8217;aimer.</p>
<h2>N&#8217;attendez pas l&#8217;Unesco</h2>
<p>Les grand médias ne parlent plus d&#8217;Internet que comme machine à fric et boîte de pandore hébergeant les menaces les plus folles.</p>
<p>C&#8217;est bien plus que ça.</p>
<p>Internet, c&#8217;est la nouvelle humanité. C&#8217;est la route la plus courte pour mettre en relation les communautés, gommer les différences d&#8217;age, de sexe, d&#8217;éducation et de milieux. Et vite.</p>
<p>C&#8217;est la démocratie et la liberté, incarnées dans un service.</p>
<p>Avec l&#8217;argent que brasse Internet, on a tendance à croire qu&#8217;il a révolutionné le business, et que c&#8217;est ce qu&#8217;il faut protéger.</p>
<p>On ne pourrait avoir plus tord.</p>
<p>Si demain Internet disparaissait, l&#8217;impact économique serait énorme, mais l&#8217;impact social serait le plus important.</p>
<p>Nous perdrions le pouvoir de parler tel qu&#8217;il existe aujourd&#8217;hui.</p>
<p>Comprenez bien, l&#8217;histoire est un cycle. On oscille entre la guerre et la paix. Entre l&#8217;abondance et la pauvreté. Entre la liberté et l&#8217;esclavage. Aucun pays, aucun peuple, aucune période n&#8217;est une exception. Notre système s&#8217;écroulera et sera remplacé par un autre. Peut être plus libre, sans doute moins. Les français connaîtrons des conflits majeurs, comme le reste du monde. Ils auront faim, puis ça ira mieux, puis ça recommencera.</p>
<p>Tout ceci est naturel.</p>
<p>La possibilité que le prochain cycle soit meilleur que le précédent dépend entièrement de notre capacité à nous éduquer les uns-les autres. Pas du haut vers le bas. Tous. Les uns les autres. Gutenberg a permis aux démocraties modernes d&#8217;exister.</p>
<p>A notre niveau de population, de consommation et potentiel d&#8217;impact nuisible en tant qu&#8217;espèce, Internet est le seul outil qui soit suffisamment efficace pour nous organiser à travailler à un avenir meilleur, plutôt que de nous entre-tuer. <strong>Et il n&#8217;a cette efficacité actuelle que parce qu&#8217;il n&#8217;est pas contrôlé par une minorité et permet à tout le monde de parler à tout le monde, de n&#8217;importe quoi, en temps réel.</strong></p>
<p>Cette minorité finira toujours par se planter sur le long terme, à cause de ses limites humaines. Par contre, la somme de l&#8217;humanité s&#8217;équilibre globalement, et d&#8217;elle émerge nos meilleurs systèmes, nos innovations, notre futur. Si on laisse un gouvernement ou une entité quelconque choisir ce que permet de faire Internet, nous attendrons ces limites, et ce sera game over. Internet jouera contre nous, plus avec nous.</p>
<p>C&#8217;est pourquoi il est primordial de ne pas considérer Internet comme un simple service.</p>
<p>C&#8217;est pourquoi il est primordial d&#8217;avoir un Internet libre et neutre.</p>
<p>C&#8217;est pourquoi il est primordial de ne pas laisser les journalistes lui coller une réputation dans un but sensationnaliste.</p>
<p>C&#8217;est pourquoi il est primordial de ne pas laisser un groupe ou un autre avoir une trop grande influence sur le réseau.</p>
<p>Internet n&#8217;est plus une expérimentation technologique, il est le support de notre avenir en tant qu&#8217;homo sapiens.</p>
<p>Cela a déjà été dit. Mon article n&#8217;a rien de nouveau. Mais cette vérité a besoin d&#8217;être répétée, martelée, car les gens oublient, se lassent, considèrent les choses les plus importantes comme acquises, et les perdent de n&#8217;avoir plus su les apprécier. Cela non plus je ne l&#8217;ai pas inventé. Je l&#8217;ai constaté à l&#8217;échelle mondiale et j&#8217;ai pu lire des milliers d&#8217;intellectuels faire le même constat en tout point du globe. Ce que je peux faire de mon bureau. Grâce à Internet.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=5819&amp;md5=19aeb0027f4082b45dd730414c1e60f2" 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=5824
title: L’encoding en Python, une bonne fois pour toute
uri: L-encoding-en-Python-une-bonne-fois-pour-toute
url: http://sametmax.com/lencoding-en-python-une-bonne-fois-pour-toute/
content:
<p>J&#8217;avais oublié la zik, je rajoute:</p>

<!-- iframe plugin v:2.3 - wordpress.org/extend/plugins/iframe/ -->
<iframe width="420" height="315" src="http://www.youtube.com/embed/8XOV2L-eM38" frameborder="0" scrolling="no" class="iframe-class"></iframe>
<p>Vous avez tous un jour eu l&#8217;erreur suivante :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #008000;">UnicodeDecodeError</span>: <span style="color: #483d8b;">'machine'</span> codec can<span style="color: #483d8b;">'t decode character '</span>trucmuche<span style="color: #483d8b;">' in position x: ordinal not in range(z)</span></pre></div></div>

<p>Et là, pour vous en sortir, vous en avez chié des ronds de paté.</p>
<p>Le problème vient du fait que la plupart du temps, ignorer l&#8217;encoding marche : nous travaillons dans des environnements homogènes et toujours avec des données dans le même format, ou un format plus ou moins compatible.</p>
<p>Mais le texte, c&#8217;est compliqué, terriblement compliqué, et le jour où ça se gâte, si vous ne savez pas ce que vous faites, vous ne vous en sortirez pas.</p>
<p>C&#8217;est d&#8217;autant plus vrai en Python car :</p>
<ul>
<li>Par défaut, Python plante sur les erreurs d&#8217;encoding là où d&#8217;autres langage (comme le PHP) se débrouillent pour vous sortir un truc (qui ne veut rien dire, qui peut corrompre toute votre base de données, mais qui ne plante pas).</li>
<li>Python est utilisé dans des environnements hétérogènes. Quand vous codez en JS sur le navigateur, vous n&#8217;avez presque jamais à vous soucier de l&#8217;encoding : le browser gère quasiment tout pour vous. En Python dès que vous allez lire un fichier et l&#8217;afficher dans un terminal, cela fait potentiellement 3 encoding différents.</li>
<li>Python 2.7 a des réglages par défaut très stricts, et pas forcément adaptés à notre informatique moderne (fichier de code en ASCII par exemple).</li>
</ul>
<p>A la fin de cet article, vous saurez vous sortir de toutes les situations merdiques liées aux encodages.</p>
<h2>Règle numéro 1 : Le texte brut n&#8217;existe pas.</h2>
<p>Quand vous avez du texte quelque part (un terminal, un fichier, une base de données&#8230;), il est forcément représenté sous forme de 0 et de 1.</p>
<p>La corrélation entre cette suite de 0 et de 1 et la lettre est faite dans un énorme tableau qui contient toutes les lettres d&#8217;un côté, et toutes les combinaisons de 0 et de 1 de l&#8217;autre. Il n&#8217;y a pas de magie. C&#8217;est un énorme tableau stocké quelque part dans votre ordinateur. <strong>Si vous n&#8217;avez pas ce tableau, vous ne pouvez pas lire du texte. Même le texte le plus simple.</strong></p>
<p>Malheureusement, au début de l&#8217;informatique, <strong>presque chaque pays a créé son propre tableau, et ces tableaux sont incompatibles entre eux</strong> : pour la même combinaison de 0 et de 1, ils donnent un caractère différent voir rien du tout.</p>
<p>La mauvaises nouvelle, c&#8217;est qu&#8217;ils sont encore utilisés aujourd&#8217;hui.</p>
<p>Ces tableaux, c&#8217;est ce qu&#8217;on appelle les encodings, et il y en a beaucoup. Voici la liste de ceux que Python gère :</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;">encodings</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">''</span>.<span style="color: black;">join</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'- '</span> + e + <span style="color: #483d8b;">'<span style="color: #000099; font-weight: bold;">\n</span>'</span> <span style="color: #ff7700;font-weight:bold;">for</span> e <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">sorted</span><span style="color: black;">&#40;</span><span style="color: #008000;">set</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">encodings</span>.<span style="color: black;">aliases</span>.<span style="color: black;">aliases</span>.<span style="color: black;">values</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
- ascii
- base64_codec
- big5
- big5hkscs
- bz2_codec
- cp037
- cp1026
- cp1140
- cp1250
- cp1251
- cp1252
- cp1253
- cp1254
- cp1255
- cp1256
- cp1257
- cp1258
- cp424
- cp437
- cp500
- cp775
- cp850
- cp852
- cp855
- cp857
- cp858
- cp860
- cp861
- cp862
- cp863
- cp864
- cp865
- cp866
- cp869
- cp932
- cp949
- cp950
- euc_jis_2004
- euc_jisx0213
- euc_jp
- euc_kr
- gb18030
- gb2312
- gbk
- hex_codec
- hp_roman8
- hz
- iso2022_jp
- iso2022_jp_1
- iso2022_jp_2
- iso2022_jp_2004
- iso2022_jp_3
- iso2022_jp_ext
- iso2022_kr
- iso8859_10
- iso8859_11
- iso8859_13
- iso8859_14
- iso8859_15
- iso8859_16
- iso8859_2
- iso8859_3
- iso8859_4
- iso8859_5
- iso8859_6
- iso8859_7
- iso8859_8
- iso8859_9
- johab
- koi8_r
- latin_1
- mac_cyrillic
- mac_greek
- mac_iceland
- mac_latin2
- mac_roman
- mac_turkish
- mbcs
- ptcp154
- quopri_codec
- rot_13
- shift_jis
- shift_jis_2004
- shift_jisx0213
- tactis
- tis_620
- utf_16
- utf_16_be
- utf_16_le
- utf_32
- utf_32_be
- utf_32_le
- utf_7
- utf_8
- uu_codec
- zlib_codec</pre></div></div>

<p>Et certains ont plusieurs noms (des alias), donc on pourrait en compter plus:</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;">len</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">encodings</span>.<span style="color: black;">aliases</span>.<span style="color: black;">aliases</span>.<span style="color: black;">keys</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #ff4500;">307</span></pre></div></div>

<p>Quand vous affichez du texte sur un terminal avec un simple <code>print</code>, votre ordinateur va implicitement chercher le tableau qu&#8217;il pense être le plus adapté, et fait la traduction. Même pour le texte le plus simple. Même pour un espace tout seul.</p>
<p><strong>Mais surtout, ça veut dire que votre propre code EST dans un encoding. Et vous DEVEZ savoir lequel.</strong></p>
<h2>Règle numéro 2 : utf8 est le langage universel, utilisez le</h2>
<p>Il existe un encoding qui essaye des regrouper toutes les langues du monde, et il s&#8217;appelle unicode. Unicode est un tableau gigantesque qui contient des combinaisons de 1 et de 0 d&#8217;un côté, et les caractères de toutes la langues possibles de l&#8217;autre : chinois, arabe, français, espagnol, russe&#8230;</p>
<p>Bon, il ne contient pas encore absolument tout, mais il couvre suffisamment de terrain pour éliminer 99.999999999 des problèmes de communications de texte entre machines dans le monde.</p>
<p>Le défaut d&#8217;unicode est qu&#8217;il est plus lent et prend plus de place que d&#8217;autres représentations du même texte. Aujourd&#8217;hui le téléphone le plus pourri à 10 fois la puissance nécessaire, et ce n&#8217;est plus un souci : il peut être utilisé presque partout (sauf peut être dans l&#8217;embarqué drastique) sans même réfléchir à la question. Tous les langages les plus importants, tous les services les plus importants, tous les logiciels les plus importants gèrent unicode.</p>
<p>Il y a plusieurs implémentations concrètes d&#8217;unicode, la plus célèbre est &#8220;UTF 8&#8243;.</p>
<p><strong>Moralité, par défaut, utilisez utf-8.</strong></p>
<p>Une fois, à l&#8217;entretien d&#8217;embauche, un mec m&#8217;avait reproché d&#8217;utiliser UTF8 parce que &#8220;ça posait des problèmes d&#8217;encoding&#8221;. Comprenez bien qu&#8217;utf-8 ne pose aucun problème d&#8217;encoding. Ce sont tous les autres codecs du monde qui posent des problèmes d&#8217;encoding. UTF-8 est certainement le seul à justement, ne poser aucun problème.</p>
<p>UTF 8 est le seul encoding vers lequel, aujourd&#8217;hui, on puisse convertir vers et depuis (pratiquement) n&#8217;importe quel autre codec du monde. C&#8217;est un espéranto. C&#8217;est une pierre de rosette. C&#8217;est au texte ce que l&#8217;or est à l&#8217;économie.</p>
<p>Si UTF8 vous pose &#8220;un problème d&#8217;encoding&#8221;, c&#8217;est que vous ne savez pas dans quel encoding votre texte est actuellement ou comment le convertir. C&#8217;est tout.</p>
<p>Il n&#8217;y a presque aucune raison de ne pas utiliser UTF8 aujourd&#8217;hui (à part sur des vieux systèmes ou des systèmes où les ressources sont tellement limitées que vous n&#8217;utiliseriez pas Python de toute façon).</p>
<p><strong>Utilisez utf8. Partout. Tout le temps.</strong></p>
<p>Si vous communiquez avec un système qui ne comprend pas UTF8, convertissez.</p>
<p>Mais gardez votre partie en UTF8.</p>
<h2>Règle numéro 3 : il faut maîtriser l&#8217;encoding de son code</h2>
<p>Le fichier dans lequel vous écrivez votre code est dans un encoding et ce n&#8217;est pas lié à votre OS. C&#8217;est votre éditeur qui s&#8217;en occupe. Apprenez à régler votre éditeur pour qu&#8217;il utilise l&#8217;encoding que vous voulez.</p>
<p>Et l&#8217;encoding que vous voulez est UTF8.</p>
<p><strong>Si vous ne savez pas dans quel encoding est votre code, vous ne pouvez pas manipuler du texte et garantir l&#8217;absence de bug.</strong></p>
<p>Vous ne POUVEZ PAS.</p>
<p>Donc réflexe : vous configurez votre éditeur de texte pour sauvegarder tous vos nouveaux fichiers par défaut en UTF8. Maintenant. Toute de suite.</p>
<p>Regardez dans la doc de l&#8217;éditeur, dans l&#8217;aide ou tapez sur Google, mais faites le.</p>
<p>Puis il faut déclarer cet encoding à la première ligne de chaque fichier de code avec l&#8217;expression suivante :</p>

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

<p>Par exemple :</p>

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

<p>C&#8217;est une spécificité de Python : si l&#8217;encoding du fichier est différent de l&#8217;encoding par défaut du langage, il faut le déclarer sinon le programme plantera à la première conversion. En Python 2.7, l&#8217;encoding par défaut est ASCII, donc il faut presque toujours le déclarer. En Python 3, l&#8217;encoding par défaut est UTF8 et on peut donc l&#8217;omettre si on l&#8217;utilise. Ce que vous allez faire après la lecture de cet article.</p>
<p>Ensuite, il existe deux types de chaînes de caractères en Python :</p>
<ul>
<li>La chaîne de caractères encodée: type &#8216;str&#8217; en Python 2.7, &#8216;byte&#8217; en Python 3.</li>
<li>La chaîne de caractères décodée: type &#8216;unicode&#8217; en Python 2.7, et &#8216;str&#8217; en python 3 (sic).</li>
</ul>
<p>Illustration :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">$ python2.7
Python 2.7.3 <span style="color: black;">&#40;</span>default, Aug  <span style="color: #ff4500;">1</span> <span style="color: #ff4500;">2012</span>, 05:<span style="color: #ff4500;">14</span>:<span style="color: #ff4500;">39</span><span style="color: black;">&#41;</span> 
<span style="color: black;">&#91;</span>GCC 4.6.3<span style="color: black;">&#93;</span> on linux2
Type <span style="color: #483d8b;">&quot;help&quot;</span>, <span style="color: #483d8b;">&quot;copyright&quot;</span>, <span style="color: #483d8b;">&quot;credits&quot;</span> <span style="color: #ff7700;font-weight:bold;">or</span> <span style="color: #483d8b;">&quot;license&quot;</span> <span style="color: #ff7700;font-weight:bold;">for</span> more information.
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #008000;">type</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'chaine'</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># bits =&gt; encodée</span>
<span style="color: #66cc66;">&lt;</span>type <span style="color: #483d8b;">'str'</span><span style="color: #66cc66;">&gt;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #008000;">type</span><span style="color: black;">&#40;</span>u<span style="color: #483d8b;">'chaine'</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># unicode =&gt; décodée</span>
<span style="color: #66cc66;">&lt;</span>type <span style="color: #483d8b;">'unicode'</span><span style="color: #66cc66;">&gt;</span></pre></div></div>


<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">$ python3
Python 3.2.3 <span style="color: black;">&#40;</span>default, Oct <span style="color: #ff4500;">19</span> <span style="color: #ff4500;">2012</span>, <span style="color: #ff4500;">20</span>:<span style="color: #ff4500;">10</span>:<span style="color: #ff4500;">41</span><span style="color: black;">&#41;</span> 
<span style="color: black;">&#91;</span>GCC 4.6.3<span style="color: black;">&#93;</span> on linux2
Type <span style="color: #483d8b;">&quot;help&quot;</span>, <span style="color: #483d8b;">&quot;copyright&quot;</span>, <span style="color: #483d8b;">&quot;credits&quot;</span> <span style="color: #ff7700;font-weight:bold;">or</span> <span style="color: #483d8b;">&quot;license&quot;</span> <span style="color: #ff7700;font-weight:bold;">for</span> more information.
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #008000;">type</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;chaine&quot;</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># unicode =&gt; decodée</span>
<span style="color: #66cc66;">&lt;</span>class <span style="color: #483d8b;">'str'</span><span style="color: #66cc66;">&gt;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #008000;">type</span><span style="color: black;">&#40;</span>b<span style="color: #483d8b;">&quot;chaine&quot;</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># bits =&gt; encodée</span>
&nbsp;
<span style="color: #66cc66;">&lt;</span>class <span style="color: #483d8b;">'bytes'</span><span style="color: #66cc66;">&gt;</span></pre></div></div>

<p>Votre but, c&#8217;est de n&#8217;avoir dans votre code que des chaînes de type &#8216;unicode&#8217;.</p>
<p>En Python 3, c&#8217;est automatique. Toutes les chaînes sont de type &#8216;unicode&#8217; (appelé &#8216;str&#8217; dans cette version, je sais, je sais, c&#8217;est confusionant à mort) par défaut.</p>
<p>En Python 2.7 en revanche, il faut préfixer la chaîne par un <code>u</code>.</p>
<p>Donc, dans votre code, TOUTES vos chaînes doivent être déclarées ainsi :</p>

<div class="wp_syntax"><div class="code"><pre class="pyhton" style="font-family:monospace;">u&quot;votre chaîne&quot;</pre></div></div>

<p>Oui, c&#8217;est chiant. Mais c&#8217;est indispensable. Encore une fois, il n&#8217;y a pas d&#8217;alternative (dites le avec la voix de Thatcher si ça vous excite).</p>
<p>Si vous voulez, vous pouvez activer le comportement de Python 3 dans Python 2.7 en mettant ceci au début de CHACUN de vos modules :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">from</span> <span style="color: #dc143c;">__future__</span> <span style="color: #ff7700;font-weight:bold;">import</span> unicode_literals</pre></div></div>

<p>Ceci n&#8217;affecte que le fichier en cours, jamais les autres modules.</p>
<p>On peut le mettre <a href="http://sametmax.com/personnalisez-le-demarrage-dipython/">au démarrage d&#8217;iPython également</a>.</p>
<p>Je résume :</p>
<ul>
<li>Réglez votre éditeur sur UTF8.</li>
<li>Mettez <code># -*- coding: utf8 -*-</code> au début de vos modules.</li>
<li>Préfixez toutes vos chaînes de <code>u</code> ou faites <code>from __future__ import unicode_literals</code> en début de chaque module.</li>
</ul>
<p>Si vous ne faites pas cela, votre code marchera. La plupart de temps. Et un jour, dans une situation particulière, il ne marchera plus. Plus du tout.</p>
<p>Oh, et ce n&#8217;est pas grave si vous avez d&#8217;anciens modules dans d&#8217;autres encodings. Tant que vous utilisez des objets &#8216;unicode&#8217; partout, ils marcheront sans problème ensemble.</p>
<h2>Règle numéro 4 : décodez toute les entrées de votre programme</h2>
<p>La partie difficile de ce conseil, c&#8217;est de savoir ce qu&#8217;est une entrée.</p>
<p>Je vais vous donner une définition simple : <strong>tout ce qui ne fait pas partie du code de votre programme et qui est traité dans votre programme est une entrée.</strong></p>
<p>Le texte des fichiers, le nom de ces fichiers, le retour des appels système, le retour d&#8217;une ligne de commande parsée, la saisie utilisateur sur un terminal, le retour d&#8217;une requête SQL, le téléchargement d&#8217;une donnée sur le Web, etc.</p>
<p>Ce sont toutes des entrées.</p>
<p><strong>Comme tous les textes du monde, les entrées sont dans un encoding. Et vous DEVEZ savoir lequel.</strong></p>
<p>Comprenez bien, si vous ne connaissez pas l&#8217;encoding de vos entrées, ça marchera la plupart du temps, et un jour, ça va planter.</p>
<p>Il n&#8217;y a pas d&#8217;alternative (bis).</p>
<p>Or, <strong>il n&#8217;y a pas de moyen de détecter un encoding de façon fiable.</strong></p>
<p>Donc, soit le fournisseur de la donnée vous donne cette information (settings dans la base de données, doc de votre logiciel, configuration de votre OS, spec du client, coup de fils au fournisseur&#8230;), soit vous êtes baisés.</p>
<p>On ne peut pas lire un simple fichier si on ne connait pas son encoding. Point.</p>
<p>Si cela a marché jusqu&#8217;ici pour vous, c&#8217;est que vous avez eu de la chance : la plupart de vos fichiers étaient dans l&#8217;encoding de votre éditeur et de votre système. Tant qu&#8217;on travaille sur sa machine, tout va bien.</p>
<p>Si vous lisez une page HTML, l&#8217;encoding est souvent déclaré dans la balise META ou dans un header.</p>
<p>Si vous écrivez dans un terminal, l&#8217;encoding du terminal est accessible avec <code>sys.(stdin|stdout).encoding</code>.</p>
<p>Si vous manipulez des noms de fichier, on peut récupérer l&#8217;encoding du file system en cours avec <code>sys.getfilesystemencoding()</code>.</p>
<p>Mais parfois il n&#8217;y a pas d&#8217;autres moyen d&#8217;obtenir cette information que de demander à la personne qui a produit la donnée. Parfois même, l&#8217;encoding déclaré est faux.</p>
<p>Dans tous les cas, vous avez besoin de cette information.</p>
<p>Et une fois que vous l&#8217;avez, il faut décoder le texte reçu.</p>
<p>La manière la plus simple de faire cela est :</p>

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

<p>Le texte sera de type &#8216;str&#8217;, et <code>decode()</code> retourne (si vous lui fournissez le bon codec ;-)), une version &#8216;unicode&#8217;.</p>
<p>Exemple, obtenir une chaîne &#8216;unicode&#8217; depuis une chaîne &#8216;str&#8217; encodée en utf8 :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> une_chaine = <span style="color: #483d8b;">'Chaîne'</span> <span style="color: #808080; font-style: italic;"># mon fichier est encodé en UTF8, donc la chaine est en UTF8</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #008000;">type</span><span style="color: black;">&#40;</span>une_chaine<span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&lt;</span>type <span style="color: #483d8b;">'str'</span><span style="color: #66cc66;">&gt;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> une_chaine = une_chaine.<span style="color: black;">decode</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'utf8'</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #008000;">type</span><span style="color: black;">&#40;</span>une_chaine<span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&lt;</span>type <span style="color: #483d8b;">'unicode'</span><span style="color: #66cc66;">&gt;</span></pre></div></div>

<p>Donc dès que vous lisez un fichier, récupérez une réponse d&#8217;une base de données ou parsez des arguments d&#8217;un terminal, appelez <code>decode()</code> sur la chaîne reçue.</p>
<h2>Règle numéro 5 : encodez toutes les sorties de votre programme</h2>
<p>La partie difficile de ce conseil, c&#8217;est de savoir ce qu&#8217;est une sortie.</p>
<p>Encore une fois, une définition simple : <strong>toute donnée que vous traitez et qui va être lue par autre chose que votre code est une sortie.</strong></p>
<p>Une <code>print</code> dans un terminal est une sortie, une <code>write()</code> dans un fichier est une sortie, un <code>UPDATE</code> en SQL est une sortie, un envoie dans une socket est un sortie, etc.</p>
<p>Le reste du monde ne peut pas lire les objets &#8216;unicode&#8217; de Python. Si vous écrivez ces objets dans un fichier, un terminal ou dans une base de données, Python va les convertir automatiquement en objet &#8216;str&#8217;, et l&#8217;encoding utilisé dépendra du contexte.</p>
<p>Malheureusement, il y a une limite à la capacité de Python à décider du bon encoding.</p>
<p>Donc, tout comme il vous faut connaitre l&#8217;encoding d&#8217;un texte en entrée, il vous faut connaitre l&#8217;encoding attendu par le système avec lequel vous communiquez en sortie : sachez quel est l&#8217;encoding du terminal, de votre base de données ou système de fichiers sur lequel vous écrivez.</p>
<p>Si vous ne pouvez pas savoir (page Web, API, etc), utilisez UTF8.</p>
<p>Pour ce faire, il suffit d&#8217;appelez <code>encode()</code> sur tout objet de type &#8216;unicode&#8217; :</p>

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

<p>Par exemple, pour convertir un objet &#8216;unicode&#8217; en &#8216;str&#8217; utf8:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> une_chaine = u<span style="color: #483d8b;">'Chaîne'</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #008000;">type</span><span style="color: black;">&#40;</span>une_chaine<span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&lt;</span>type <span style="color: #483d8b;">'unicode'</span><span style="color: #66cc66;">&gt;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> une_chaine = une_chaine.<span style="color: black;">encode</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'utf8'</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #008000;">type</span><span style="color: black;">&#40;</span>une_chaine<span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&lt;</span>type <span style="color: #483d8b;">'str'</span><span style="color: #66cc66;">&gt;</span></pre></div></div>

<h2>Résumé des règles</h2>
<ol>
<li>Le texte brut n&#8217;existe pas.</li>
<li>Utilisez UTF8. Maintenant. Partout.</li>
<li>Dans votre code, spécifiez l&#8217;encoding du fichier et déclarez vos chaînes comme &#8216;unicode&#8217;.</li>
<li>À l&#8217;entrée, connaissez l&#8217;encoding de vos données, et décodez avec <code>decode()</code>.</li>
<li>A la sortie, encodez dans l&#8217;encoding attendu par le système qui va recevoir la données, ou si vous ne pouvez pas savoir, en UTF8, avec <code>encode()</code>.</li>
</ol>
<p>Je sais que ça vous démange de voir un cas concret, alors voici un pseudo programme (<a href="https://github.com/sametmax/codes-des-articles/blob/master/2013/avril/encoding.py">téléchargeable ici</a>) :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># -*- coding: utf-8 -*-</span>
&nbsp;
&nbsp;
<span style="color: #808080; font-style: italic;"># toutes les chaines sont en unicode (même les docstrings)</span>
<span style="color: #ff7700;font-weight:bold;">from</span> <span style="color: #dc143c;">__future__</span> <span style="color: #ff7700;font-weight:bold;">import</span> unicode_literals
&nbsp;
<span style="color: #483d8b;">&quot;&quot;&quot;
    Un script tout pourri qui télécharge plein de page et les sauvegarde
    dans une base de données sqlites.
&nbsp;
    On écrit dans un fichier de log les opérations effectuées.
&quot;&quot;&quot;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">re</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> sqlite3
&nbsp;
pages = <span style="color: black;">&#40;</span>
    <span style="color: black;">&#40;</span><span style="color: #483d8b;">'Snippets de Sebsauvage'</span>, <span style="color: #483d8b;">'http://www.sebsauvage.net/python/snyppets/'</span><span style="color: black;">&#41;</span>,
    <span style="color: black;">&#40;</span><span style="color: #483d8b;">'Top 50 de bashfr'</span>, <span style="color: #483d8b;">'http://danstonchat.com/top50.html'</span><span style="color: black;">&#41;</span>,
<span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># création de la base de données</span>
conn = sqlite3.<span style="color: black;">connect</span><span style="color: black;">&#40;</span>r<span style="color: #483d8b;">&quot;backup.db&quot;</span><span style="color: black;">&#41;</span>
c = conn.<span style="color: black;">cursor</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">try</span>:
    c.<span style="color: black;">execute</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">''</span><span style="color: #483d8b;">'
        CREATE TABLE pages (
            id INTEGER PRIMARY KEY,
            nom TEXT,
            html TEXT
        )'</span><span style="color: #483d8b;">''</span>
    <span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">except</span> sqlite3.<span style="color: black;">OperationalError</span>:
    <span style="color: #ff7700;font-weight:bold;">pass</span>
&nbsp;
log = <span style="color: #008000;">open</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'backup.log'</span>, <span style="color: #483d8b;">'wa'</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">for</span> nom, page <span style="color: #ff7700;font-weight:bold;">in</span> pages:
&nbsp;
    <span style="color: #808080; font-style: italic;"># ceci est une manière très fragile de télécharger et</span>
    <span style="color: #808080; font-style: italic;"># parser du HTML. Utilisez plutôt scrapy et beautifulsoup</span>
    <span style="color: #808080; font-style: italic;"># si vous faites un vrai crawler</span>
    response = <span style="color: #dc143c;">urllib2</span>.<span style="color: black;">urlopen</span><span style="color: black;">&#40;</span>page<span style="color: black;">&#41;</span>
    html = response.<span style="color: black;">read</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">100000</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># je récupère l'encoding à l'arrache</span>
    encoding = <span style="color: #dc143c;">re</span>.<span style="color: black;">findall</span><span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'&lt;meta.*?charset=[&quot;<span style="color: #000099; font-weight: bold;">\'</span>]*(.+?)[&quot;<span style="color: #000099; font-weight: bold;">\'</span>&gt;]'</span>, html, flags=<span style="color: #dc143c;">re</span>.<span style="color: black;">I</span><span style="color: black;">&#41;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># html devient de l'unicode</span>
    html = html.<span style="color: black;">decode</span><span style="color: black;">&#40;</span>encoding<span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># ici je peux faire des traitements divers et varié avec ma chaîne</span>
    <span style="color: #808080; font-style: italic;"># et en fin de programme...</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># la lib sqlite convertie par défaut tout objet unicode en UTF8</span>
    <span style="color: #808080; font-style: italic;"># car c'est l'encoding de sqlite par défaut donc passer des chaînes</span>
    <span style="color: #808080; font-style: italic;"># unicode marche, et toutes les chaînes de mon programme sont en unicode</span>
    <span style="color: #808080; font-style: italic;"># grace à mon premier import</span>
    c.<span style="color: black;">execute</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;&quot;&quot;INSERT INTO pages (nom, html) VALUES (?, ?)&quot;&quot;&quot;</span>, <span style="color: black;">&#40;</span>nom, html<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># j'écris dans mon fichier en UTF8 car c'est ce que je veux pouvoir lire</span>
    <span style="color: #808080; font-style: italic;"># plus tard</span>
    msg = u<span style="color: #483d8b;">&quot;Page '{}' sauvée<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span>.<span style="color: black;">format</span><span style="color: black;">&#40;</span>nom<span style="color: black;">&#41;</span>
    log.<span style="color: black;">write</span><span style="color: black;">&#40;</span>msg.<span style="color: black;">encode</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'utf8'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># notez que si je ne fais pas encode(), soit:</span>
    <span style="color: #808080; font-style: italic;"># - j'ai un objet 'unicode' et ça plante</span>
    <span style="color: #808080; font-style: italic;"># - j'ai un objet 'str' et ça va marcher mais mon fichier contiendra</span>
    <span style="color: #808080; font-style: italic;">#   l'encoding de la chaîne initiale (qui ici serait aussi UTF8, mais</span>
    <span style="color: #808080; font-style: italic;">#   ce n'est pas toujours le cas)</span>
&nbsp;
conn.<span style="color: black;">commit</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
c.<span style="color: black;">close</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
log.<span style="color: black;">close</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></div></div>

<h2>Quelques astuces</h2>
<p>Certaines bibliothèques acceptent indifféremment des objets &#8216;unicode&#8217; et &#8216;str&#8217; :</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;">logging</span> <span style="color: #ff7700;font-weight:bold;">import</span> basicConfig, getLogger
<span style="color: #66cc66;">&gt;&gt;&gt;</span> basicConfig<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> log = getLogger<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> log.<span style="color: black;">warn</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Détécé&quot;</span><span style="color: black;">&#41;</span>
WARNING:root:Détécé
<span style="color: #66cc66;">&gt;&gt;&gt;</span> log.<span style="color: black;">warn</span><span style="color: black;">&#40;</span>u<span style="color: #483d8b;">&quot;Détécé&quot;</span><span style="color: black;">&#41;</span>
WARNING:root:Détécé</pre></div></div>

<p>Et ce n&#8217;est pas forcément une bonne chose car si il y a derrière écriture dans un fichier de log, cela peut poser problème.</p>
<p>D&#8217;autres ont besoin qu&#8217;on leur précise:</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;">re</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">re</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #dc143c;">re</span>.<span style="color: black;">search</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'é'</span>, <span style="color: #483d8b;">'télé'</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&lt;</span>_sre.<span style="color: black;">SRE_Match</span> <span style="color: #008000;">object</span> at 0x7fa4d3f77238<span style="color: #66cc66;">&gt;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #dc143c;">re</span>.<span style="color: black;">search</span><span style="color: black;">&#40;</span>u<span style="color: #483d8b;">'é'</span>, u<span style="color: #483d8b;">'télé'</span>, <span style="color: #dc143c;">re</span>.<span style="color: black;">UNICODE</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&lt;</span>_sre.<span style="color: black;">SRE_Match</span> <span style="color: #008000;">object</span> at 0x7fa4d3f772a0<span style="color: #66cc66;">&gt;</span></pre></div></div>

<p>Le module <code>re</code> par exemple aura des résultats biaisés sur une chaîne &#8216;unicode&#8217; si on ne précise pas le flag <code>re.UNICODE</code>.</p>
<p>D&#8217;autres n&#8217;acceptent pas d&#8217;objet &#8216;str&#8217;:</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> io
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #66cc66;">&gt;&gt;&gt;</span> io.<span style="color: #dc143c;">StringIO</span><span style="color: black;">&#40;</span>u<span style="color: #483d8b;">'é'</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&lt;</span>_io.<span style="color: #dc143c;">StringIO</span> <span style="color: #008000;">object</span> at 0x14a96d0<span style="color: #66cc66;">&gt;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> io.<span style="color: #dc143c;">StringIO</span><span style="color: black;">&#40;</span>u<span style="color: #483d8b;">'é'</span>.<span style="color: black;">encode</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'utf8'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
Traceback <span style="color: black;">&#40;</span>most recent call last<span style="color: black;">&#41;</span>:
  File <span style="color: #483d8b;">&quot;&lt;ipython-input-5-16988a0d4ac4&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>
    io.<span style="color: #dc143c;">StringIO</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'é'</span>.<span style="color: black;">encode</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'utf8'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #008000;">TypeError</span>: initial_value must be <span style="color: #008000;">unicode</span> <span style="color: #ff7700;font-weight:bold;">or</span> <span style="color: #008000;">None</span>, <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #008000;">str</span></pre></div></div>

<p>D&#8217;autres encore n&#8217;acceptent pas d&#8217;objet &#8216;unicode&#8217;:</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;">base64</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #dc143c;">base64</span>.<span style="color: black;">encodestring</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'é'</span>.<span style="color: black;">encode</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'utf8'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #483d8b;">'w6k=<span style="color: #000099; font-weight: bold;">\n</span>'</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #dc143c;">base64</span>.<span style="color: black;">encodestring</span><span style="color: black;">&#40;</span>u<span style="color: #483d8b;">'é'</span><span style="color: black;">&#41;</span>
Traceback <span style="color: black;">&#40;</span>most recent call last<span style="color: black;">&#41;</span>:
  File <span style="color: #483d8b;">&quot;&lt;ipython-input-3-1714982ca68e&gt;&quot;</span>, line <span style="color: #ff4500;">1</span>, <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #66cc66;">&lt;</span>module<span style="color: #66cc66;">&gt;</span>
    <span style="color: #dc143c;">base64</span>.<span style="color: black;">encodestring</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'é'</span><span style="color: black;">&#41;</span>
  File <span style="color: #483d8b;">&quot;/usr/lib/python2.7/base64.py&quot;</span>, line <span style="color: #ff4500;">315</span>, <span style="color: #ff7700;font-weight:bold;">in</span> encodestring
    pieces.<span style="color: black;">append</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">binascii</span>.<span style="color: black;">b2a_base64</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">chunk</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #008000;">UnicodeEncodeError</span>: <span style="color: #483d8b;">'ascii'</span> codec can<span style="color: #483d8b;">'t encode character u'</span>\xe9<span style="color: #483d8b;">' in position 0: ordinal not in range(128)</span></pre></div></div>

<p>Cela peut être pour des raison de performances (certaines opérations sont plus rapides sur un objet &#8216;str&#8217;), ou pour des raisons historiques, d&#8217;ignorance ou de paresse.</p>
<p>Vous ne pouvez pas le deviner à l&#8217;avance. Souvent c&#8217;est marqué dans la doc, sinon il faut tester dans le shell.</p>
<p>Une bibliothèque bien faite demandera de l&#8217;unicode et vous retournera de l&#8217;unicode, vous libérant l&#8217;esprit. Par exemple, <a href="sametmax.com/sept-petites-libs-qui-changent-la-vie-dun-dev-python/">requests</a> et l&#8217;ORM <a href="http://sametmax.com/quels-gros-sites-sont-faits-en-django/">Django</a> le font, et communiquent avec le reste du monde (en l&#8217;occurence le Web et les bases de données) dans le meilleur encoding possible automatiquement de manière transparente. Quand c&#8217;est possible bien entendu, parfois il faudra forcer l&#8217;encoding car le fournisseur de votre donnée déclare le mauvais. Vous n&#8217;y pouvez rien, c&#8217;est pareil pour tous les langages du monde.</p>
<p>Enfin il existe des raccourcis pour certaines opérations, utilisez les autant que possible. Par exemple, pour lire un fichier, au lieu de faire un simple <code>open()</code>, vous pouvez faire :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">from</span> <span style="color: #dc143c;">codecs</span> <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #008000;">open</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># open() de codec à exactement la même API, y compris avec &quot;with&quot;</span>
f = <span style="color: #008000;">open</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'fichier'</span>, encoding=<span style="color: #483d8b;">'encoding'</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Les chaînes récupérées seront automatiquement sous forme d&#8217;objet &#8216;unicode&#8217; au lieu d&#8217;objet &#8216;str&#8217; qu&#8217;il vous aurait fallut convertir à la main.</p>
<h2>Les outils de la dernières chance</h2>
<p>Je vous ai menti, si vous ne connaissez pas l&#8217;encoding de vos entrées ou de vos sorties, il vous reste encore quelques options.</p>
<p>Sachez cependant que ces options sont des hacks, des trucs à tenter quand tout ce qui a été décrit plus haut a foiré.</p>
<p>Si vous faites bien votre boulot, ça ne doit pas arriver souvent. Une à deux fois max dans votre année, sauf environnement de travail très très merdique.</p>
<p>D&#8217;abord, parlons de l&#8217;entrée.</p>
<p>Si vous recevez un objet et qu&#8217;il vous est impossible de trouver l&#8217;encoding, vous pouvez forcer un décodage imparfait avec <code>decode()</code> en spécifiant le paramètre <code>error</code>.</p>
<p>Il peut prendre les valeurs suivantes :</p>
<ul>
<li><code>'strict'</code> : lever une exception en cas d&#8217;erreur. C&#8217;est le comportement par défaut.</li>
<li><code>'ignore'</code> : tout caractère qui provoque une erreur est ignoré.</li>
<li><code>'replace'</code> : tout caractère qui provoque une erreur est remplacé par un point d&#8217;interrogation.</li>
</ul>

<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;">print</span> <span style="color: #483d8b;">'Père Noël'</span>.<span style="color: black;">decode</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'ascii'</span><span style="color: black;">&#41;</span>
Traceback <span style="color: black;">&#40;</span>most recent call last<span style="color: black;">&#41;</span>:
  File <span style="color: #483d8b;">&quot;&lt;stdin&gt;&quot;</span>, line <span style="color: #ff4500;">1</span>, <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #66cc66;">&lt;</span>module<span style="color: #66cc66;">&gt;</span>
<span style="color: #008000;">UnicodeDecodeError</span>: <span style="color: #483d8b;">'ascii'</span> codec can<span style="color: #483d8b;">'t decode byte 0xc3 in position 1: ordinal not in range(128)
&gt;&gt;&gt; print '</span>Pè<span style="color: #dc143c;">re</span> Noël<span style="color: #483d8b;">'.decode('</span>ascii<span style="color: #483d8b;">', errors='</span>ignore<span style="color: #483d8b;">')
Pre Nol
&gt;&gt;&gt; print '</span>Pè<span style="color: #dc143c;">re</span> Noël<span style="color: #483d8b;">'.decode('</span>ascii<span style="color: #483d8b;">', errors='</span>replace<span style="color: #483d8b;">')
P��re No��l</span></pre></div></div>

<p>Mozilla vient également à la rescousse avec sa lib <a href="https://pypi.python.org/pypi/chardet">chardet</a> qu&#8217;il faut donc <a href="http://sametmax.com/votre-python-aime-les-pip/">installer</a> :</p>

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

<p>Et qui TENTE (du verbe &#8216;tenter&#8217;, &#8220;qui essaye&#8221;, et qui donc peut échouer et se tromper) de détecter l&#8217;encoding utilisé.</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> chardet.<span style="color: black;">detect</span><span style="color: black;">&#40;</span>u<span style="color: #483d8b;">'Le Père Noël est une ordure'</span>.<span style="color: black;">encode</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'utf8'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: black;">&#123;</span><span style="color: #483d8b;">'confidence'</span>: <span style="color: #ff4500;">0.8063275188616134</span>, <span style="color: #483d8b;">'encoding'</span>: <span style="color: #483d8b;">'ISO-8859-2'</span><span style="color: black;">&#125;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> chardet.<span style="color: black;">detect</span><span style="color: black;">&#40;</span>u<span style="color: #483d8b;">&quot;Le Père Noël est une ordure j'ai dis enculé&quot;</span>.<span style="color: black;">encode</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'utf8'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: black;">&#123;</span><span style="color: #483d8b;">'confidence'</span>: <span style="color: #ff4500;">0.87625</span>, <span style="color: #483d8b;">'encoding'</span>: <span style="color: #483d8b;">'utf-8'</span><span style="color: black;">&#125;</span></pre></div></div>

<p>Cela marche pas trop mal, mais n&#8217;attendez pas de miracles. Plus il y a de texte, plus c&#8217;est précis, et plus le paramètre <code>confidence</code> est proche de 1.</p>
<p>Parlons maintenant de la sortie, c&#8217;est à dire le cas où le système qui va recevoir vos données est une grosse quiche qui plante dès qu&#8217;on lui donne autre chose que de l&#8217;ASCII.</p>
<p>Je ne veux balancer personne, mais mon regard se tourne vers l&#8217;administration américaine. Subtilement. De manière insistante.</p>
<p>D&#8217;abord, <code>encode()</code> accepte les mêmes valeurs pour <code>errors</code> que <code>decode()</code>. Mais en prime, il accepte <code>'xmlcharrefreplace'</code>, très pratique pour les fichiers XML :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> u<span style="color: #483d8b;">&quot;Et là-bas, tu vois, c'est la coulée du grand bronze&quot;</span>.<span style="color: black;">encode</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'ascii'</span>, errors=<span style="color: #483d8b;">'xmlcharrefreplace'</span><span style="color: black;">&#41;</span>
<span style="color: #483d8b;">&quot;Et l&amp;#224;-bas, tu vois, c'est la coul&amp;#233;e du grand bronze&quot;</span></pre></div></div>

<p>Enfin, on peut essayer d&#8217;obtenir un texte potable en remplaçant les caractères spéciaux par leur équivalent ASCII le plus proche.</p>
<p>Avec l&#8217;alphabet latin, c&#8217;est très facile :</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: #dc143c;">unicodedata</span>.<span style="color: black;">normalize</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'NFKD'</span>, u<span style="color: #483d8b;">&quot;éçûö&quot;</span><span style="color: black;">&#41;</span>.<span style="color: black;">encode</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'ascii'</span>, <span style="color: #483d8b;">'ignore'</span><span style="color: black;">&#41;</span>
<span style="color: #483d8b;">'ecuo'</span></pre></div></div>

<p>Pour des trucs plus avancés comme le cyrilique ou le mandarin, il faut installer <a href="https://pypi.python.org/pypi/Unidecode">unidecode</a> :</p>

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


<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> unidecode <span style="color: #ff7700;font-weight:bold;">import</span> unidecode
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">print</span> unidecode<span style="color: black;">&#40;</span>u<span style="color: #483d8b;">&quot;En russe, Moscou s'écrit Москва&quot;</span><span style="color: black;">&#41;</span>
En russe, Moscou s<span style="color: #483d8b;">'ecrit Moskva</span></pre></div></div>

 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=5824&amp;md5=05190c7a671c3edf8834c6f0cb8a00ba" 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=5849
title: Créer un snippet pour Sublime Text
uri: Créer-un-snippet-pour-Sublime-Text
url: http://sametmax.com/creer-un-snippet-pour-sublime-text/
content:
<p>Un petit truc sympa avec Sublime Text c&#8217;est les snippets. une sorte de bout de code qui permet de faciliter la vie à bon nombre de feignasses dont je fais partie.<br />
Ce bout de code va vous permettre d&#8217;afficher du texte prédéfini lorsque vous rentrerez le mot-clef correspondant suivi de la touche Tab.</p>
<p><strong>Dans Sublime:</strong><br />
Dans tools &gt; New Snippet. Vous allez voir apparaître un squelette d&#8217;un snippet prérempli.<br />
Modifiez-le pour obtenir le code suivant.</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;!</span>-- Un snippet pour afficher une balise pre pour mes articles wordpress --<span style="color: #000000; font-weight: bold;">&gt;</span>
<span style="color: #000000; font-weight: bold;">&lt;</span>snippet<span style="color: #000000; font-weight: bold;">&gt;</span>
	<span style="color: #000000; font-weight: bold;">&lt;</span>content<span style="color: #000000; font-weight: bold;">&gt;&lt;!</span><span style="color: #7a0874; font-weight: bold;">&#91;</span>CDATA<span style="color: #7a0874; font-weight: bold;">&#91;</span>
<span style="color: #000000; font-weight: bold;">&lt;</span> pre <span style="color: #007800;">lang</span>=<span style="color: #ff0000;">&quot;bash&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span><span style="color: #007800;">$SELECTION</span><span style="color: #000000; font-weight: bold;">&lt;/</span> pre<span style="color: #000000; font-weight: bold;">&gt;</span>
<span style="color: #7a0874; font-weight: bold;">&#93;</span><span style="color: #7a0874; font-weight: bold;">&#93;</span><span style="color: #000000; font-weight: bold;">&gt;&lt;/</span>content<span style="color: #000000; font-weight: bold;">&gt;</span>
	<span style="color: #000000; font-weight: bold;">&lt;</span>tabTrigger<span style="color: #000000; font-weight: bold;">&gt;</span>pre<span style="color: #000000; font-weight: bold;">&lt;/</span>tabTrigger<span style="color: #000000; font-weight: bold;">&gt;</span>
	<span style="color: #000000; font-weight: bold;">&lt;!</span>-- Optional: Set a scope to limit where the snippet will trigger --<span style="color: #000000; font-weight: bold;">&gt;</span>
	<span style="color: #000000; font-weight: bold;">&lt;!</span>-- <span style="color: #000000; font-weight: bold;">&lt;</span>scope<span style="color: #000000; font-weight: bold;">&gt;</span>source.python<span style="color: #000000; font-weight: bold;">&lt;/</span>scope<span style="color: #000000; font-weight: bold;">&gt;</span> --<span style="color: #000000; font-weight: bold;">&gt;</span>
<span style="color: #000000; font-weight: bold;">&lt;/</span>snippet<span style="color: #000000; font-weight: bold;">&gt;</span></pre></div></div>

<p><strong>Content:</strong><br />
Content va contenir le texte à afficher, vous avez la possibilité d&#8217;y ajouter des <a href="http://sublimetext.info/docs/en/extensibility/snippets.html">variables d&#8217;environnement</a> comme récupérer le texte sélectionné avant le déclenchement du snippet (var: $SELECTION)</p>
<p><strong>tabTrigger:</strong><br />
c&#8217;est le mot-clef suivi de la touche TAB qui va déclencher l&#8217;insertion du snippet, en général je prends les premières lettre du snippet que je veux déclencher (ipdb, pre, biatch)</p>
<p><strong>scope:</strong><br />
Va définir le type d&#8217;environnement dans lequel on va pouvoir executer le snippet, source.python ne proposera le snippet que dans du code python. source.php pour php, etc.</p>
<p>Sauvegardez votre snippet et dans le cas présent entrez le mot-clef &#8220;pre&#8221; suivit de la touche TAB et ho miracle un joli texte prérempli apparaît. Si vous avez sélectionné du texte avant il sera inclu à la place de la variable $SELECTION (d&#8217;ailleurs à ce propos je n&#8217;ai pas trouvé comment le faire tout au clavier sans passer par le menu tools &gt; snippet car la selection est remplacée par le mot-clef au clavier).</p>
<p>ATTENTION: sauvegardez bien votre snippet avec l&#8217;extension sublime-snippet sinon vous ne verrez pas apparaître votre snippet lors de son invocation.</p>
<p>Il y a <a href="http://sublimetext.info/docs/en/extensibility/snippets.html">d&#8217;autres options</a> comme préremplir des bout de texte ou utiliser des regex.</p>
<p>J&#8217;en use et en abuse comme toute bonne feignasse qui se respecte.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=5849&amp;md5=2a380d74083830158865c9512594d7e4" 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=5860
title: Monitorez vos serveurs avec munin et notifications par email
uri: Monitorez-vos-serveurs-avec-munin-et-notifications-par-email
url: http://sametmax.com/monitorez-vos-serveurs-avec-munin-et-notifications-par-email/
content:
<p>Avoir un serveur c&#8217;est bien, en prendre soins c&#8217;est mieux. J&#8217;ai longtemps administré des serveurs sans trop me soucier de ce qui pouvait leur arriver et bien des fois tout a planté car je n&#8217;avais pas su anticiper la catastrophe.<br />
Un exemple courant, j&#8217;ai viré Apache pour installer Nginx et ce dernier log par defaut les acces http, après quelques semaines, le disque dur bien rempli, le serveur me claque dans les doigts, plus de place, tout merde, c&#8217;est le drâme, pas moyen de rebooter à part en safe mode car disque plein, les hémoroïdes s&#8217;en mêle, c&#8217;est foutu.</p>
<p>J&#8217;ai commencé par <a href="http://oss.oetiker.ch/mrtg/">MRTG</a>, pas terrible à installer mais il fait son boulot. Et puis j&#8217;ai changé de serveurs pas mal de fois en une année, horrible d&#8217;avoir à réinstaller ce truc à chaque fois alors j&#8217;ai cherché autre chose, après quelques tests pas terribles je suis tombé sur munin, plutôt complet avec des plugins que l&#8217;on peut écrire soit-même. Facile à installer quand on utilise les packages, suivez le guide.</p>
<p><strong>Installation de <a>Munin</a>:</strong><br />
Munin se compose de deux programmes.<br />
<strong>Le maître (munin):</strong> qui va récupérer les infos et générer les graphs.<br />
<strong>Le noeud (munin-node):</strong> qui s&#8217;installe sur tous les serveurs à monitorer y compris le maître si besoin et qui va envoyer les infos au maître.</p>
<p><strong>Sur le serveur Maître pour une distribution Ubuntu:</strong></p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #c20cb9; font-weight: bold;">apt-get</span> <span style="color: #c20cb9; font-weight: bold;">install</span> munin munin-node munin-plugins-extra
<span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #c20cb9; font-weight: bold;">ln</span> <span style="color: #660033;">-s</span> <span style="color: #000000; font-weight: bold;">/</span>var<span style="color: #000000; font-weight: bold;">/</span>cache<span style="color: #000000; font-weight: bold;">/</span>munin<span style="color: #000000; font-weight: bold;">/</span>www <span style="color: #000000; font-weight: bold;">/</span>var<span style="color: #000000; font-weight: bold;">/</span>www<span style="color: #000000; font-weight: bold;">/</span>munin
<span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #000000; font-weight: bold;">/</span>etc<span style="color: #000000; font-weight: bold;">/</span>init.d<span style="color: #000000; font-weight: bold;">/</span>munin-node restart</pre></div></div>

<p>Pour voir s&#8217;afficher les pages il vous faudra un serveur web, exemple avec Nginx:<br />
dans le répertoire conf.d de Nginx ajoutez un fichier munin.conf et mettez-y le code suivant.</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">vi</span> <span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>local<span style="color: #000000; font-weight: bold;">/</span>nginx<span style="color: #000000; font-weight: bold;">/</span>conf.d<span style="color: #000000; font-weight: bold;">/</span>munin.conf</pre></div></div>


<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">server <span style="color: #7a0874; font-weight: bold;">&#123;</span>
&nbsp;
    listen       <span style="color: #000000;">80</span>;
    server_name munin.monserveur.com;
&nbsp;
	location <span style="color: #000000; font-weight: bold;">/</span> <span style="color: #7a0874; font-weight: bold;">&#123;</span>
	        auth_basic            <span style="color: #ff0000;">&quot;Restricted&quot;</span>;
	        <span style="color: #666666; font-style: italic;"># Create the htpasswd file with the htpasswd tool.</span>
	        auth_basic_user_file  <span style="color: #000000; font-weight: bold;">/</span>etc<span style="color: #000000; font-weight: bold;">/</span>nginx<span style="color: #000000; font-weight: bold;">/</span>htpasswd;
&nbsp;
	        root <span style="color: #000000; font-weight: bold;">/</span>var<span style="color: #000000; font-weight: bold;">/</span>www<span style="color: #000000; font-weight: bold;">/</span>munin<span style="color: #000000; font-weight: bold;">/</span>;
	        index  index.html index.htm;
	        expires modified +310s;
	<span style="color: #7a0874; font-weight: bold;">&#125;</span>
<span style="color: #7a0874; font-weight: bold;">&#125;</span></pre></div></div>

<p>Note: vous pouvez désactiver l&#8217;authentification si vous voulez rendre votre page publique.</p>
<p>Après réglages de vos DNS chez votre registrar vous devriez avoir quelque chose à la page <strong>http://munin.monserveur.com</strong></p>
<p><strong>Sur les serveurs à monitorer (les noeuds):</strong></p>

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

<p>Il faut maintenant &#8220;dire&#8221; au serveur noeud l&#8217;IP du serveur maître pour qu&#8217;il puisse lui envoyer les informations sur l&#8217;état de la machine.</p>
<p>Editez le fichier /etc/munin/munin-node.conf</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">allow ^<span style="color: #000000;">192</span>\.168\.1\.200$</pre></div></div>

<p>Cette partie va permettre au Maître de venir récupérer les infos nécessaires. Remplacez l&#8217;IP par celle de votre serveur Maître.</p>
<p>On redemarre munin-node pour prendre en compte les changements.</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #000000; font-weight: bold;">/</span>etc<span style="color: #000000; font-weight: bold;">/</span>init.d<span style="color: #000000; font-weight: bold;">/</span>munin-node restart</pre></div></div>

<p>PS: Si il ne se passe rien vérifiez que vous n&#8217;avez pas un firewall qui bloque l&#8217;IP et/ou le port TCP/4949</p>
<p><strong>Les plugins:</strong><br />
Les plugins sont des petits programmes permettant de rajouter des fonctionnalitées au monitoring comme la supervision de services tels que Redis, Varnish, Nginx, etc. <a href="https://github.com/munin-monitoring/contrib/tree/master/plugins">La liste est ici</a></p>
<p>Attention: L&#8217;ajout des plugins se fait côté serveur Noeud !</p>
<p>En fait il s&#8217;agit de simples liens symboliques dans le répertoire <strong>/etc/munin/plugins/</strong> pointants vers le répertoire <strong>/usr/share/munin/plugins/</strong>.<br />
La liste des plugins disponibles s&#8217;obtient avec:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">sudo</span> munin-node-configure</pre></div></div>

<p><strong>Exemple rajouter le plugin pour monitorer Mysql:</strong></p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">ln</span> <span style="color: #660033;">-s</span> <span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>share<span style="color: #000000; font-weight: bold;">/</span>munin<span style="color: #000000; font-weight: bold;">/</span>plugins<span style="color: #000000; font-weight: bold;">/</span>mysql_queries <span style="color: #000000; font-weight: bold;">/</span>etc<span style="color: #000000; font-weight: bold;">/</span>munin<span style="color: #000000; font-weight: bold;">/</span>plugins<span style="color: #000000; font-weight: bold;">/</span>mysql_queries</pre></div></div>

<div id="attachment_5863" class="wp-caption aligncenter" style="width: 626px"><img class=" wp-image-5863 " title="Mysql monitoré, il en chie des briques là..." src="media/6634dd63.munin.png" data-original-source="http://sametmax.com/wp-content/uploads/2013/04/munin.png" alt="" width="616" height="418" /><p class="wp-caption-text">Mysql en train de mourir...</p></div>
<p><strong>Après que les machines noeuds aient été configurées on les déclarent au serveur Maître:</strong><br />
Il faut éditer le fichier munin.conf sur le serveur Maître.</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">vi</span>  <span style="color: #000000; font-weight: bold;">/</span>etc<span style="color: #000000; font-weight: bold;">/</span>munin<span style="color: #000000; font-weight: bold;">/</span>munin.conf</pre></div></div>


<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #7a0874; font-weight: bold;">&#91;</span>sametmax<span style="color: #7a0874; font-weight: bold;">&#93;</span>
    address sametmax.com
    df._home.warning <span style="color: #000000;">95</span>
    use_node_name <span style="color: #c20cb9; font-weight: bold;">yes</span>
&nbsp;
<span style="color: #7a0874; font-weight: bold;">&#91;</span>machine_locale_maitre<span style="color: #7a0874; font-weight: bold;">&#93;</span>
    address  127.0.0.1
    use_node_name <span style="color: #c20cb9; font-weight: bold;">yes</span>
&nbsp;
<span style="color: #7a0874; font-weight: bold;">&#91;</span>groupe_de_serveurs;<span style="color: #7a0874; font-weight: bold;">&#93;</span>
    address  127.0.0.1
    use_node_name <span style="color: #c20cb9; font-weight: bold;">yes</span>
&nbsp;
<span style="color: #7a0874; font-weight: bold;">&#91;</span>groupe_de_serveurs;serveur_adolf<span style="color: #7a0874; font-weight: bold;">&#93;</span>
    address  33.94.124.33
    use_node_name <span style="color: #c20cb9; font-weight: bold;">yes</span>
&nbsp;
<span style="color: #7a0874; font-weight: bold;">&#91;</span>groupe_de_serveurs;serveur_himler<span style="color: #7a0874; font-weight: bold;">&#93;</span>
    address  33.94.124.33
    use_node_name <span style="color: #c20cb9; font-weight: bold;">yes</span>
&nbsp;
<span style="color: #7a0874; font-weight: bold;">&#91;</span>groupe_de_serveurs;serveur_DSK<span style="color: #7a0874; font-weight: bold;">&#93;</span>
    address  69.69.69.69
    use_node_name <span style="color: #c20cb9; font-weight: bold;">yes</span></pre></div></div>

<p><strong>Analysons la config ci-dessus:</strong></p>
<p><em>sametmax:</em><br />
Le premier va nous sortir les stats du serveur sametmax.com, on peut mettre l&#8217;ip comme le nom de domaine.</p>
<p><em>machine_locale_maitre:</em><br />
Si on veut monitorer la machine maitre on met 127.0.0.1</p>
<p><em>groupe_de_serveurs:</em><br />
Va définir un groupe de serveurs, l&#8217;affichage groupera tous les serveurs y appartenant, c&#8217;est juste pour un affichage plus clair, ne pas oublier le &#8220;;&#8221; à la fin</p>
<p><em>groupe_de_serveurs;serveur_adolf:</em><br />
Un serveur qui apparaîtra dans le groupe de serveurs avec himler et DSK</p>
<p><strong>Notification par email:</strong><br />
Avec munin il est possible de recevoir des notifications lorsque certains capteurs de votre monitoring atteignent un certain seuil.</p>
<p>Vérifiez bien que sendmail est installé et qu&#8217;il <a href="http://stackoverflow.com/questions/10359437/sendmail-how-to-configure-sendmail-on-ubuntu">fonctionne</a><br />
Dans le shell on teste sendmail</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">'Promo sur les BBW'</span> <span style="color: #000000; font-weight: bold;">|</span> mail <span style="color: #660033;">-s</span> <span style="color: #ff0000;">'sujet à poil les putes'</span> monmail<span style="color: #000000; font-weight: bold;">@</span>moi.com</pre></div></div>

<p><strong>Toujours dans le fichier munin.conf sur le serveur Maître:</strong></p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">#email notifications settings</span>
contacts max
contact.max.command mail <span style="color: #660033;">-s</span> <span style="color: #ff0000;">&quot;Munin notif <span style="color: #007800;">${var:host}</span>&quot;</span> monmail<span style="color: #000000; font-weight: bold;">@</span>moi.com
contact.max.always_send warning critical</pre></div></div>

<p>La premiere ligne définie un contact, la deuxième va envoyer l&#8217;email de notification via sendmail au mail indiqué.<br />
La dernière ligne va indiquer à munin qu&#8217;il faut envoyer les alertes pour les <em>warning</em> et les <em>critical</em>.</p>
<p>Les seuils pour les notifications sont définis par warning et critical. Regardez plus haut pour le serveur [sametmax] nous avons défini un seuil pour df (disk free) de 95%.</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #7a0874; font-weight: bold;">&#91;</span>sametmax<span style="color: #7a0874; font-weight: bold;">&#93;</span>
    address sametmax.com
    df._home.warning <span style="color: #000000;">95</span>
    use_node_name <span style="color: #c20cb9; font-weight: bold;">yes</span></pre></div></div>

<p>Ce qui veut dire que lorsque l&#8217;usage disque de<strong> /home</strong> aura dépassé les 95% d&#8217;utilisation munin va vous envoyer une notification par email. ça peut devenir lourd à la longue par contre car il s&#8217;arrête jamais :)</p>
<p><b>On redémarre munin sur le serveur mettre pour prendre en compte les modif:</b></p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">su</span> - munin <span style="color: #660033;">--shell</span>=<span style="color: #000000; font-weight: bold;">/</span>bin<span style="color: #000000; font-weight: bold;">/</span><span style="color: #c20cb9; font-weight: bold;">bash</span>
<span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>share<span style="color: #000000; font-weight: bold;">/</span>munin<span style="color: #000000; font-weight: bold;">/</span>munin-update</pre></div></div>

<p>Bon monitorage!</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=5860&amp;md5=f8555e58642f9ccb20c6b2bc0898e138" 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=5868
title: Debuggez django avec –trace
uri: Debuggez-django-avec-trace
url: http://sametmax.com/debuggez-django-avec-trace/
content:
<p>C&#8217;est con mais toujours bon ça savoir : si <code>manage.py</code> ou <code>django-admin</code> vous font des misères, vous pouvez les rendre plus verbeuses avec l&#8217;option <code>--trace</code>.</p>
<p>Par défaut, elles n&#8217;affichent qu&#8217;un message, avec cette option on se retrouve avec le stack trace complet et surtout l&#8217;exception levée.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=5868&amp;md5=927e439783192d2bef0fb816e1afbbfd" 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=5879
title: Pourquoi les éditeurs s’en foutent que les DRM n’empêchent pas le piratage
uri: Pourquoi-les-éditeurs-s-en-foutent-que-les-DRM-n-empêchent-pas-l
url: http://sametmax.com/pourquoi-les-editeurs-sen-foutent-que-les-drm-nempechent-pas-le-piratage/
content:
<p>Ce qui m&#8217;a toujours amusé avec les activistes, c&#8217;est leur capacité à s&#8217;exclamer devant la bêtise de ceux qu&#8217;ils critiquent alors qu&#8217;ils n&#8217;ont simplement pas compris leurs motivations.</p>
<p>Par exemple, dans le cas des DRM, le débat est orienté sur leur efficacité. J&#8217;ai été le premier à dire : &#8220;les DRM, c&#8217;est idiot, ça n&#8217;a jamais empêché le piratage.&#8221;</p>
<p>Sauf que ce n&#8217;est pas le but.</p>
<p>C&#8217;est le but annoncé, certes, car il faut bien le vendre à l&#8217;état et l&#8217;opinion publique. Mais c&#8217;est comme la pédophilie, les néo-nazis, les terroristes et le petit déjeuner équilibré, simplement quelque chose qu&#8217;on brandit en avant pour que les gens dépensent leur énergie sur ce débat alors que la stratégie est ailleurs.</p>
<p>Le but premier des DRM est le contrôle du marché. C&#8217;est simplement la bonne vieille stratégie des formats qu&#8217;on a vu évoluer dans les années 90 avec la bureautique qui s&#8217;est adaptée.</p>
<p>Aujourd&#8217;hui les informaticiens sont OPÉ sur les formats, il savent qu&#8217;ils faut se méfier. Et les gens aussi.</p>
<p>Alors on vend des formats ouverts, et on colle juste des mesures de protections par dessus. C&#8217;est la même chose, mais en différent.</p>
<p>Cette stratégie de répéter encore et toujours le même procédé sous une forme différente à toujours marché à travers l&#8217;histoire. Les gens ont de la mémoire, mais pas l&#8217;opinion publique et le débat, ainsi que tous les efforts de ceux qui ont combattu pour éviter la merde de la vague précédente, vont devoir repartir de zéro.</p>
<p>Pour les fournisseurs de DRM, c&#8217;est tout bénef :</p>
<ul>
<li>Ils passent pour des héros défenseurs contre les méchants pirates aux yeux des industriels.</li>
<li>Ils s&#8217;assurent de controler les fournisseurs de logiciels et de matériels : une fois le DRM adopté, le fournisseur est locké dans cette solution, c&#8217;est un marché captif. Comme à l&#8217;époque de la guéguerre des formats.</li>
<li>Par cascade, on lock aussi le consommateur lambda. Oui les alternatives et les solutions de contournement existent, mais <a href="http://sametmax.com/il-ne-faut-pas-prendre-des-gens-pour-des-cons-mais-ne-jamais-oublier-quils-en-sont/">l&#8217;utilisateur moyen ne sait pas installer un exe</a>, alors bypasser une protection avec un outil, mouarf.</li>
<li>Une fois la masse critique atteinte, on domine toute la chaîne de production : on peut imposer ses prix, d&#8217;autres services intermédiaires, voir carrément proposer ses propres boutiques pour rayer nos anciens fournisseurs de la carte.</li>
</ul>
<p>Rien d&#8217;étonnant que les DRM soient donc fournis avant tout par des éditeurs de solutions (MS, Apple, Adobe), et pas du tout par les éditeurs de contenu : le but est le contrôle du marché en jouant sur la peur des majors, pas du tout d&#8217;éviter le piratage.</p>
<p>Et cet article ne sert à rien. Car seuls ceux qui sont déjà convaincus de l&#8217;importance d&#8217;éviter les DRM vont le lire. Ils vont essayer de se débattre, et puis pouf, on changera de cheval de bataille. On ressortira la même sauce, mais en différent. </p>
<p>Par exemple, les DRM, ça ne sert à rien si on a pas une bonne authentification.</p>
<p>On parie que le prochain débat, c&#8217;est une solution d&#8217;identification unique de chaque usager pour éviter le terrorisme, le plagiat, l&#8217;appel à la haine et la diffamation ? L&#8217;anonymat et le vol d&#8217;identité c&#8217;est grave ma p&#8217;tite dame. Et les activistes derrière : ouiiiii, mais c&#8217;est une atteinte à la liberté, tout ça ! Et ce sera vrai. Mais ce sera encore un faux débat, car derrière, les gars veulent juste contrôler la chaîne de diffusion des produits.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=5879&amp;md5=028f338aa7d2f76a1593535307cbfc83" 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=5885
title: L’erreur “broken pipe” avec les serveurs Python tel Gunicorn
uri: L-erreur-broken-pipe-avec-les-serveurs-Python-tel-Gunicorn
url: http://sametmax.com/lerreur-broken-pipe-avec-les-serveurs-python-tel-gunicorn/
content:
<p>Quand on commence à avoir pas mal de trafic sur son site, on commence à noter l&#8217;apparition d&#8217;une erreur inquiétante :</p>
<p><code>Traceback (most recent call last):<br />
  File "gunicorn/workers/async.py", line 44, in handle<br />
    self.handle_request(req, client, addr)<br />
  File "gunicorn/workers/ggevent.py", line 88, in handle_request<br />
    super(GeventWorker, self).handle_request(*args)<br />
  File "gunicorn/workers/async.py", line 83, in handle_request<br />
    resp.write(item)<br />
  File "gunicorn/http/wsgi.py", line 275, in write<br />
    util.write(self.sock, arg, self.chunked)<br />
  File "gunicorn/util.py", line 232, in write<br />
    sock.sendall(data)<br />
  File "gevent/socket.py", line 480, in sendall<br />
    data_sent += self.send(_get_memory(data, data_sent), flags)<br />
  File "gevent/socket.py", line 451, in send<br />
    return sock.send(data, flags)<br />
error: [Errno 32] Broken pipe</code></p>
<p>Et plus il y a de trafic, plus cette erreur apparait dans les logs.</p>
<p>Pourtant, impossible de trouver la cause de l&#8217;erreur, tout semble bien marcher, le serveur pète la forme et <a href="http://sametmax.com/debugger-en-python-les-bases-de-pdb/">ipdb</a> ne donne rien du tout.</p>
<p>La raison pour laquelle vous ne trouvez rien, c&#8217;est qu&#8217;il n&#8217;y a rien à trouver. Cette erreur est levée par le module socket quand il essaye d&#8217;écrire sur une connexion qui s&#8217;est fermée brutalement.</p>
<p>Or le serveur ne peut pas savoir quand une connexion s&#8217;est fermée si le client ne lui envoie pas le message. Et il peut y avoir énormément de raisons pour que ça arrive : fermeture d&#8217;un onglet en plein chargement, crash du navigateur, extinction du PC pendant la réponse, etc.</p>
<p>Vous en voyez plus quand le trafic augmente tout simplement parce que statistiquement, avec plus de visiteurs, ces situations rares se rencontrent plus facilement dans la masse de connexions.</p>
<p>Donc pour l&#8217;erreur &#8220;broken pipe&#8221;, il n&#8217;y a rien à faire, à part de monter le log level de votre serveur d&#8217;un cran pour qu&#8217;il n&#8217;affiche plus ça dans vos logs.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=5885&amp;md5=43ae25e4c07b60f641fe8afcd9b664d4" 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=5842
title: Desinstaller VMware sous Ubuntu
uri: Desinstaller-VMware-sous-Ubuntu
url: http://sametmax.com/desinstaller-vmware-sous-ubuntu/
content:
<p>Un jour j&#8217;ai installé VMWare, puis je l&#8217;ai oublié. Le jour où mon petit disque SSD m&#8217;a rappelé qu&#8217;on était pas encore dans les To dans sa gamme de prix, j&#8217;ai voulu le désinstaller et faire de la place.</p>
<p>Problème : il n&#8217;est pas listé dans les paquets.</p>
<p>En fait VMWare s&#8217;installe avec un script à leur sauce, et se désinstalle de la même façon.</p>
<p>Il faut d&#8217;abord faire :</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ vmware-installer <span style="color: #660033;">-l</span></pre></div></div>

<p>Pour lister leurs produits installés.</p>
<p>Puis <code>vmware-installer --uninstall-product leur_produit</code>, dans mon cas :</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">sudo</span> vmware-installer <span style="color: #660033;">--uninstall-product</span> vmware-workstation</pre></div></div>

<p>P.S: je redécouvre l&#8217;extension Firefox <a href="https://addons.mozilla.org/en-US/firefox/addon/its-all-text/">It&#8217;s all text</a>. Avec un Sublime Text derrière, c&#8217;est fantastique. Je <kbd>Ctrl</kbd> + <kbd>Alt</kbd> + <kbd>W</kbd> à mort.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=5842&amp;md5=81d76a5a559e00964953b659d29a0fba" 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=5902
title: ImportError: cannot import name MAXREPEAT
uri: ImportError-cannot-import-name-MAXREPEAT
url: http://sametmax.com/importerror-cannot-import-name-maxrepeat/
content:
<p>Vous avez mis à jour votre Python (par exemple avec homebrew ou en faisait une upgrade d&#8217;Ubuntu), et soudainement, BAM, tout exécution dans un <a href="http://sametmax.com/les-environnement-virtuels-python-virtualenv-et-virtualenvwrapper/">virtualenv</a> vous balance un gros <code>ImportError: cannot import name MAXREPEAT</code> à la tronche.</p>
<p>J&#8217;ai vu des tas de propositions pour résoudre ça, certains à base de <a href="http://www.isotope11.com/blog/fix-your-python-2-dot-7-4-maxrepeat-importerror-issues">réinstallation</a> sous Mac, d&#8217;autres à base d&#8217;<a href="https://bugs.launchpad.net/ubuntu/+source/python2.7/+bug/1157687">édition de fichiers</a> source Python sous Debian.</p>
<p>Personnellement j&#8217;utilise une autre solution, un peu chiante, mais beaucoup plus propre, qui consiste simplement à appeler la commande <code>virtualenv</code> sur le dossier qui contient l&#8217;env. Par exemple :</p>
<p><code>virtualenv ~/.virtualenvs/test</code></p>
<p>Je dis un peu chiante car :</p>
<ul>
<li>Si on a beaucoup d&#8217;env, il faut le faire une fois par env.</li>
<li>Et si on a des options genre <code>-p</code>, il faut les repasser telles qu&#8217;on les a passé à l&#8217;origine (et allez vous souvenir de ça pour un env qui a 6 mois) sinon on pête l&#8217;env.</li>
</ul>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=5902&amp;md5=9d97c173d4a07d3ccd38d1999961ddb7" 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=5912
uri: 2013-04-28-Le-guide-ultime-et-définitif-sur-la-programmation-orientée-objet-en
title:
Le guide ultime et définitif sur la programmation orientée objet en Python à l’usage des débutants qui sont rassurés par les textes détaillés qui prennent le temps de tout expliquer. Partie 7.

url:
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-7/

content:
<p>Un peu de rock à l&#8217;anglaise pour faire passer la pilule :</p>

<!-- iframe plugin v:2.3 - wordpress.org/extend/plugins/iframe/ -->
<iframe width="420" height="315" src="http://www.youtube.com/embed/wcb4gCJ9da0" frameborder="0" scrolling="no" class="iframe-class"></iframe>
<p>Après avoir lu <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">la partie précédente</a>, vous avez dû vous demander comment mettre tout ça en application.</p>
<p>Comme je vous l&#8217;avais expliqué, l&#8217;orienté object est particulièrement adapté à la création de belles APIs. Nous allons donc étudier aujourd&#8217;hui un cas réel de mise en pratique réussi avec la lib <a href="https://github.com/jaraco/path.py">path.py</a>.</p>
<p>J&#8217;ai choisi cette lib car :</p>
<ul>
<li>Le code tient dans un seul fichier.</li>
<li>Il y a plein de patterns utilisés dedans qui sont intéressant à expliquer.</li>
<li>C&#8217;est une source propre qui suit globalement les bonnes pratiques.</li>
<li>Path.py a une API élégante, donc le résultat à l&#8217;usage est un bon exemple.</li>
</ul>
<p>Petit rappel, path.py est une surcouche au dessus des modules <a href="http://docs.python.org/2/library/tempfile.html?highlight=tempfile#tempfile">tempfile</ ahref=>, <a href="http://docs.python.org/2/library/os.html?highlight=os#os">os</a> ou encore <a href="http://docs.python.org/2/library/shutil.html?highlight=shutils">shutil</a>, c&#8217;est à dire qu&#8217;elle permet de faire exactement la même chose, en plus pratique.</p>
<p>C&#8217;est donc typiquement un bibliothèque de confort, et elle n&#8217;aurait aucun intérêt si elle n&#8217;était pas agréable à utiliser puisque l&#8217;on peut déjà faire tout ce qu&#8217;elle fait avec Python en standard. Son attractivité réside dans la beauté de son interface qui rend la manipulation de fichiers très intuitive :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># elle permet de manipuler des chemins facilement</span>
<span style="color: #ff7700;font-weight:bold;">from</span> path <span style="color: #ff7700;font-weight:bold;">import</span> path
dossier = path<span style="color: black;">&#40;</span><span style="color: #483d8b;">'/etc'</span><span style="color: black;">&#41;</span>
fichier = dossier / <span style="color: #483d8b;">'postgresql/9.1/main/pg_hba.conf'</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># d'obtenir des informations sur le fichier</span>
fichier.<span style="color: black;">exists</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #808080; font-style: italic;">## True</span>
fichier.<span style="color: black;">parent</span>
<span style="color: #808080; font-style: italic;">## path(u'/etc/postgresql/9.1/main')</span>
fichier.<span style="color: black;">basename</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #808080; font-style: italic;">## path(u'pg_hba.conf')</span>
fichier.<span style="color: black;">dirname</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #808080; font-style: italic;">## path(u'/etc/postgresql/9.1/main')</span>
fichier.<span style="color: black;">spli</span>
fichier.<span style="color: black;">split</span>       fichier.<span style="color: black;">splitall</span>    fichier.<span style="color: black;">splitdrive</span>  fichier.<span style="color: black;">splitext</span>    fichier.<span style="color: black;">splitlines</span>  fichier.<span style="color: black;">splitpath</span>   fichier.<span style="color: black;">splitunc</span>
fichier.<span style="color: black;">splitext</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #808080; font-style: italic;">## (path(u'/etc/postgresql/9.1/main/pg_hba'), u'.conf')</span>
&nbsp;
&nbsp;
<span style="color: #808080; font-style: italic;"># lister les fichiers dans un dossiers</span>
<span style="color: #ff7700;font-weight:bold;">for</span> fichier <span style="color: #ff7700;font-weight:bold;">in</span> dossier.<span style="color: black;">listdir</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
...     <span style="color: #ff7700;font-weight:bold;">print</span> fichier
...
<span style="color: #808080; font-style: italic;">## /etc/thunderbird</span>
<span style="color: #808080; font-style: italic;">## /etc/libpaper.d</span>
<span style="color: #808080; font-style: italic;">## /etc/mtools.conf</span>
<span style="color: #808080; font-style: italic;">## ...</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># lister récursivement les fichiers dans un dossier</span>
<span style="color: #ff7700;font-weight:bold;">for</span> fichier <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: black;">&#40;</span>dossier / <span style="color: #483d8b;">'apt/'</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> fichier
...
<span style="color: #808080; font-style: italic;">## /etc/apt/sources.list.save</span>
<span style="color: #808080; font-style: italic;">## /etc/apt/sources.list</span>
<span style="color: #808080; font-style: italic;">## /etc/apt/trusted.gpg</span>
<span style="color: #808080; font-style: italic;">## /etc/apt/trusted.gpg~</span>
<span style="color: #808080; font-style: italic;">## /etc/apt/sources.list.d/indicator-brightness-ppa-raring.list.save</span>
<span style="color: #808080; font-style: italic;">## /etc/apt/sources.list.d/tualatrix-ppa-raring.list</span>
<span style="color: #808080; font-style: italic;">## /etc/apt/sources.list.d/webupd8team-sublime-text-2-raring.list</span>
<span style="color: #808080; font-style: italic;">## /etc/apt/sources.list.d/fossfreedom-byzanz-raring.list.save</span>
<span style="color: #808080; font-style: italic;">## /etc/apt/sources.list.d/hotot-team-ppa-raring.list.save</span>
<span style="color: #808080; font-style: italic;">## /etc/apt/sources.list.d/webupd8team-y-ppa-manager-raring.list</span>
<span style="color: #808080; font-style: italic;">## /etc/apt/sources.list.d/pitti-postgresql-raring.list.save</span>
<span style="color: #808080; font-style: italic;">## /etc/apt/sources.list.d/pitti-postgresql-raring.list</span>
<span style="color: #808080; font-style: italic;">## /etc/apt/sources.list.d/yorba-ppa-raring.list.save</span>
<span style="color: #808080; font-style: italic;">## /etc/apt/sources.list.d/indicator-brightness-ppa-raring.list</span>
<span style="color: #808080; font-style: italic;">## /etc/apt/sources.list.d/webupd8team-sublime-text-2-raring.list.save</span>
<span style="color: #808080; font-style: italic;">## /etc/apt/sources.list.d/yorba-ppa-raring.list</span>
<span style="color: #808080; font-style: italic;">## /etc/apt/sources.list.d/webupd8team-y-ppa-manager-raring.list.save</span>
<span style="color: #808080; font-style: italic;">## /etc/apt/sources.list.d/fossfreedom-byzanz-raring.list</span>
<span style="color: #808080; font-style: italic;">## /etc/apt/trustdb.gpg</span>
<span style="color: #808080; font-style: italic;">## /etc/apt/apt.conf.d/20dbus</span>
<span style="color: #808080; font-style: italic;">## /etc/apt/apt.conf.d/10periodic</span>
<span style="color: #808080; font-style: italic;">## /etc/apt/apt.conf.d/99synaptic</span>
<span style="color: #808080; font-style: italic;">## /etc/apt/apt.conf.d/70debconf</span>
<span style="color: #808080; font-style: italic;">## /etc/apt/apt.conf.d/05aptitude</span>
<span style="color: #808080; font-style: italic;">## /etc/apt/apt.conf.d/20archive</span>
<span style="color: #808080; font-style: italic;">## /etc/apt/apt.conf.d/01autoremove</span>
<span style="color: #808080; font-style: italic;">## /etc/apt/apt.conf.d/50unattended-upgrades</span>
<span style="color: #808080; font-style: italic;">## /etc/apt/apt.conf.d/00aptitude</span>
<span style="color: #808080; font-style: italic;">## /etc/apt/apt.conf.d/99update-notifier</span>
<span style="color: #808080; font-style: italic;">## /etc/apt/apt.conf.d/15update-stamp</span>
<span style="color: #808080; font-style: italic;">## /etc/apt/apt.conf.d/00trustcdrom</span>
<span style="color: #808080; font-style: italic;">## /etc/apt/apt.conf.d/20changelog</span>
<span style="color: #808080; font-style: italic;">## /etc/apt/apt.conf.d/01autoremove-kernels</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># et bien d'autres choses</span></pre></div></div>

<p>Nous allons donc commenter son code, dans le cadre du tuto (on ne va pas voir les algos en détails). Je mettrai mes commentaires entre <code>#< sm ></ sm ></code> afin de les distinguer du reste.</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">&nbsp;
<span style="color: #808080; font-style: italic;">#&lt;sm&gt;</span>
<span style="color: #808080; font-style: italic;"># On commence par un bon gros bloc de copyright, sachant que path.py est</span>
<span style="color: #808080; font-style: italic;"># sous MIT License. Le plus inhabituel c'est l'absence de déclaration</span>
<span style="color: #808080; font-style: italic;"># d'encoding en en-tête, qui s'explique par le fait que toute la lib est</span>
<span style="color: #808080; font-style: italic;"># écrite uniquement avec des caractères ASCII, ce qui est l'encodage par</span>
<span style="color: #808080; font-style: italic;"># défaut de Python 2.7. Python 3 a UTF8 en encodage par défaut, mais ASCII</span>
<span style="color: #808080; font-style: italic;"># est un sous-ensemble de UTF8, donc ça ne pose pas de problème.</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Notez qu'avec mes commentaires en plus, ça ferait planter le script puisque</span>
<span style="color: #808080; font-style: italic;"># j'utilise des accents.</span>
<span style="color: #808080; font-style: italic;">#&lt;/sm&gt;</span>
&nbsp;
<span style="color: #808080; font-style: italic;">#</span>
<span style="color: #808080; font-style: italic;"># Copyright (c) 2010 Mikhail Gusarov</span>
<span style="color: #808080; font-style: italic;">#</span>
<span style="color: #808080; font-style: italic;"># Permission is hereby granted, free of charge, to any person obtaining a copy</span>
<span style="color: #808080; font-style: italic;"># of this software and associated documentation files (the &quot;Software&quot;), to deal</span>
<span style="color: #808080; font-style: italic;"># in the Software without restriction, including without limitation the rights</span>
<span style="color: #808080; font-style: italic;"># to use, copy, modify, merge, publish, distribute, sublicense, and/or sell</span>
<span style="color: #808080; font-style: italic;"># copies of the Software, and to permit persons to whom the Software is</span>
<span style="color: #808080; font-style: italic;"># furnished to do so, subject to the following conditions:</span>
<span style="color: #808080; font-style: italic;">#</span>
<span style="color: #808080; font-style: italic;"># The above copyright notice and this permission notice shall be included in all</span>
<span style="color: #808080; font-style: italic;"># copies or substantial portions of the Software.</span>
<span style="color: #808080; font-style: italic;">#</span>
<span style="color: #808080; font-style: italic;"># THE SOFTWARE IS PROVIDED &quot;AS IS&quot;, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR</span>
<span style="color: #808080; font-style: italic;"># IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,</span>
<span style="color: #808080; font-style: italic;"># FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE</span>
<span style="color: #808080; font-style: italic;"># AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER</span>
<span style="color: #808080; font-style: italic;"># LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,</span>
<span style="color: #808080; font-style: italic;"># OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE</span>
<span style="color: #808080; font-style: italic;"># SOFTWARE.</span>
<span style="color: #808080; font-style: italic;">#</span>
&nbsp;
<span style="color: #808080; font-style: italic;">#&lt;sm&gt;</span>
<span style="color: #808080; font-style: italic;"># La docstring du module qui documente l'usage général du module. En</span>
<span style="color: #808080; font-style: italic;"># l'occurence au moins l'existence de la classe principale et son usage. Les</span>
<span style="color: #808080; font-style: italic;"># symboles comme '\x40' sont juste une autre représentation d'un caractères</span>
<span style="color: #808080; font-style: italic;"># via sa valeur dans la table ASCII.</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Par exemple, '@' est à la case 64 dans la table ASCII, et 64 se note 40 en</span>
<span style="color: #808080; font-style: italic;"># hexadecimal:</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># &gt;&gt;&gt; ord('@')</span>
<span style="color: #808080; font-style: italic;"># 64</span>
<span style="color: #808080; font-style: italic;"># &gt;&gt;&gt; int('40', base=16)</span>
<span style="color: #808080; font-style: italic;"># 64</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Du coup on peut écrire '@' juste avec un caractère d’échappement en Python</span>
<span style="color: #808080; font-style: italic;"># qui va faire le lien. Cette technique est utile si on peut faire passer</span>
<span style="color: #808080; font-style: italic;"># du texte avec des caractères spéciaux dans certains protocole, par exemple</span>
<span style="color: #808080; font-style: italic;"># quand on veut rentrer un email dans une URL. En l'occurence je ne vois</span>
<span style="color: #808080; font-style: italic;"># absolument pas ce que ça vient foutre ici.</span>
<span style="color: #808080; font-style: italic;">#&lt;/sm&gt;</span>
&nbsp;
&nbsp;
<span style="color: #483d8b;">&quot;&quot;&quot; path.py - An object representing a path to a file or directory.
&nbsp;
Original author:
 Jason Orendorff &lt;jason.orendorff<span style="color: #000099; font-weight: bold;">\x</span>40gmail<span style="color: #000099; font-weight: bold;">\x</span>2ecom&gt;
&nbsp;
Current maintainer:
 Jason R. Coombs &lt;jaraco@jaraco.com&gt;
&nbsp;
Contributors:
 Mikhail Gusarov &lt;dottedmag@dottedmag.net&gt;
 Marc Abramowitz &lt;marc@marc-abramowitz.com&gt;
 Jason R. Coombs &lt;jaraco@jaraco.com&gt;
 Jason Chu &lt;jchu@xentac.net&gt;
 Vojislav Stojkovic &lt;vstojkovic@syntertainment.com&gt;
&nbsp;
Example::
&nbsp;
    from path import path
    d = path('/home/guido/bin')
    for f in d.files('*.py'):
        f.chmod(0755)
&nbsp;
path.py requires Python 2.5 or later.
&quot;&quot;&quot;</span>
&nbsp;
&nbsp;
<span style="color: #808080; font-style: italic;">#&lt;sm&gt;</span>
<span style="color: #808080; font-style: italic;"># Import du mot clé with, car cette lib est compatible avec Python 2.5</span>
<span style="color: #808080; font-style: italic;"># et le keyword est apparu en 2.6. Il a été backporté dans __future__</span>
<span style="color: #808080; font-style: italic;">#&lt;/sm&gt;</span>
<span style="color: #ff7700;font-weight:bold;">from</span> <span style="color: #dc143c;">__future__</span> <span style="color: #ff7700;font-weight:bold;">import</span> with_statement
&nbsp;
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">sys</span> <span style="color: #808080; font-style: italic;">#&lt;sm&gt;Informations sur le système&lt;/sm&gt;</span>
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">warnings</span> <span style="color: #808080; font-style: italic;">#&lt;sm&gt;Alertes techniques à d'autres dev&lt;/sm&gt;</span>
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">os</span> <span style="color: #808080; font-style: italic;">#&lt;sm&gt;Manipulation du FS&lt;/sm&gt;</span>
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">fnmatch</span> <span style="color: #808080; font-style: italic;">#&lt;sm&gt;Pattern matching comme dans un shell&lt;/sm&gt;</span>
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">glob</span> <span style="color: #808080; font-style: italic;">#&lt;sm&gt;Lister des fichier avec la syntax shell&lt;/sm&gt;</span>
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">shutil</span> <span style="color: #808080; font-style: italic;">#&lt;sm&gt;Manipulation de fichiers de haut niveau&lt;/sm&gt;</span>
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">codecs</span> <span style="color: #808080; font-style: italic;">#&lt;sm&gt;Encoding&lt;/sm&gt;</span>
<span style="color: #ff7700;font-weight:bold;">import</span> hashlib <span style="color: #808080; font-style: italic;">#&lt;sm&gt;Sommes de controle&lt;/sm&gt;</span>
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">errno</span> <span style="color: #808080; font-style: italic;">#&lt;sm&gt;Les code d'erreurs liées au fichier.&lt;/sm&gt;</span>
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">tempfile</span> <span style="color: #808080; font-style: italic;">#&lt;sm&gt;Création de fichiers temporaires&lt;/sm&gt;</span>
<span style="color: #ff7700;font-weight:bold;">import</span> functools <span style="color: #808080; font-style: italic;">#&lt;sm&gt;Manipulation des fonctions&lt;/sm&gt;</span>
&nbsp;
<span style="color: #808080; font-style: italic;">#&lt;sm&gt;</span>
<span style="color: #808080; font-style: italic;"># Tentative d'utilisation de la lib win32security qui sert à gérer</span>
<span style="color: #808080; font-style: italic;"># des aspects sécuritaires du FS sous Windows. C'est une lib tièrce partie,</span>
<span style="color: #808080; font-style: italic;"># et une dépendance ooptionelle, donc l'import est géré pour ne pas faire</span>
<span style="color: #808080; font-style: italic;"># d'erreur si la lib n'est pas disponible.</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Idem pour pwd qui est dans la lib standard mais uniquement sur les distribs</span>
<span style="color: #808080; font-style: italic;"># unix et qui donne accès aux infos sur l'utilisateur du système, tester</span>
<span style="color: #808080; font-style: italic;"># son mot de passe, etc.</span>
<span style="color: #808080; font-style: italic;">#&lt;/sm&gt;</span>
<span style="color: #ff7700;font-weight:bold;">try</span>:
    <span style="color: #ff7700;font-weight:bold;">import</span> win32security
<span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">ImportError</span>:
    <span style="color: #ff7700;font-weight:bold;">pass</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">try</span>:
    <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">pwd</span>
<span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">ImportError</span>:
    <span style="color: #ff7700;font-weight:bold;">pass</span>
&nbsp;
&nbsp;
&nbsp;
<span style="color: #808080; font-style: italic;">#&lt;sm&gt;</span>
<span style="color: #808080; font-style: italic;"># Manière standard de lister la version de la lib dans un module Python.</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># __all__ est une variable magique qui peut contenir une liste des noms de</span>
<span style="color: #808080; font-style: italic;"># tout ce qui est importable dans le module, de telle sorte que si</span>
<span style="color: #808080; font-style: italic;"># quelqu'un fait : from path import *, seul le contenu de __all__ soit</span>
<span style="color: #808080; font-style: italic;"># importé.</span>
<span style="color: #808080; font-style: italic;">#&lt;/sm&gt;</span>
__version__ = <span style="color: #483d8b;">'3.0'</span>
__all__ = <span style="color: black;">&#91;</span><span style="color: #483d8b;">'path'</span><span style="color: black;">&#93;</span>
&nbsp;
&nbsp;
<span style="color: #808080; font-style: italic;">#&lt;sm&gt;</span>
<span style="color: #808080; font-style: italic;"># Les warning ressemblent beaucoup aux exceptions excepté qu'ils ne font</span>
<span style="color: #808080; font-style: italic;"># pas planter le programme. Ici donc, ou hérite de la base des warnings</span>
<span style="color: #808080; font-style: italic;"># comme on le ferait pour créer son Exception personnalisée, ce qui va</span>
<span style="color: #808080; font-style: italic;"># permettre à l'utilisateur de la lib path.py de, plus tard, pouvoir filter</span>
<span style="color: #808080; font-style: italic;"># ce warning en particulier.</span>
<span style="color: #808080; font-style: italic;">#&lt;/sm&gt;</span>
&nbsp;
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> TreeWalkWarning<span style="color: black;">&#40;</span><span style="color: #008000;">Warning</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">pass</span>
&nbsp;
&nbsp;
<span style="color: #808080; font-style: italic;">#&lt;sm&gt;</span>
<span style="color: #808080; font-style: italic;"># Un decorateur de mémorisation, c'est à dire qui va mettre en cache les</span>
<span style="color: #808080; font-style: italic;"># résultats de la fonction sur lequel il est appliqué afin que les prochains</span>
<span style="color: #808080; font-style: italic;"># appels avec les mêmes paramètres lisent les valeurs du cache en mémoire</span>
<span style="color: #808080; font-style: italic;"># plutôt que de refaire l'opération.</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Il est utilisé plus bas sur :</span>
&nbsp;
<span style="color: #808080; font-style: italic;">#     @classmethod</span>
<span style="color: #808080; font-style: italic;">#     @simple_cache</span>
<span style="color: #808080; font-style: italic;">#     def using_module(cls, module):</span>
<span style="color: #808080; font-style: italic;">#         subclass_name = cls.__name__ + '_' + module.__name__</span>
<span style="color: #808080; font-style: italic;">#         bases = (cls,)</span>
<span style="color: #808080; font-style: italic;">#         ns = {'module': module}</span>
<span style="color: #808080; font-style: italic;">#         return type(subclass_name, bases, ns)</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Ça évitera plusieurs traitements de using_module() si le paramètre de</span>
<span style="color: #808080; font-style: italic;"># 'module' ne change pas.</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Et oui, on peut mélanger plusieurs classes et fonctions dans un même module,</span>
<span style="color: #808080; font-style: italic;"># ça n'a pas d'importance.</span>
&nbsp;
<span style="color: #808080; font-style: italic;">#&lt;/sm&gt;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> simple_cache<span style="color: black;">&#40;</span>func<span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot;
    Save results for the 'using_module' classmethod.
    When Python 3.2 is available, use functools.lru_cache instead.
    &quot;&quot;&quot;</span>
    saved_results = <span style="color: black;">&#123;</span><span style="color: black;">&#125;</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> wrapper<span style="color: black;">&#40;</span>cls, module<span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">if</span> module <span style="color: #ff7700;font-weight:bold;">in</span> saved_results:
            <span style="color: #ff7700;font-weight:bold;">return</span> saved_results<span style="color: black;">&#91;</span>module<span style="color: black;">&#93;</span>
        saved_results<span style="color: black;">&#91;</span>module<span style="color: black;">&#93;</span> = func<span style="color: black;">&#40;</span>cls, module<span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> saved_results<span style="color: black;">&#91;</span>module<span style="color: black;">&#93;</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> wrapper
&nbsp;
&nbsp;
<span style="color: #808080; font-style: italic;">#&lt;sm&gt;</span>
<span style="color: #808080; font-style: italic;"># Nous avons vu que les propriétés permettaient de déguiser une méthode</span>
<span style="color: #808080; font-style: italic;"># en attribut. Cela ne marche pas sur une méthode de classe car dans ce cas</span>
<span style="color: #808080; font-style: italic;"># la propriété va se retourner elle-même.</span>
<span style="color: #808080; font-style: italic;"># Cette classe hérite de property pour écraser ce comportement et bien</span>
<span style="color: #808080; font-style: italic;"># retourner la valeur de la méthode de classe.</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Elle est utilisée plus loin dans:</span>
&nbsp;
<span style="color: #808080; font-style: italic;">#     @ClassProperty</span>
<span style="color: #808080; font-style: italic;">#     @classmethod</span>
<span style="color: #808080; font-style: italic;">#     def _next_class(cls):</span>
<span style="color: #808080; font-style: italic;">#         &quot;&quot;&quot;</span>
<span style="color: #808080; font-style: italic;">#         What class should be used to construct new instances from this class</span>
<span style="color: #808080; font-style: italic;">#         &quot;&quot;&quot;</span>
<span style="color: #808080; font-style: italic;">#         return cls</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Ce qui va permettre de faire path._next_class au lieu de path._next_class().</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># C'est cosmétique, mais c'est le but de la lib d'être jolie.</span>
<span style="color: #808080; font-style: italic;">#&lt;/sm&gt;</span>
<span style="color: #ff7700;font-weight:bold;">class</span> ClassProperty<span style="color: black;">&#40;</span><span style="color: #008000;">property</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__get__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, cls, owner<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;">fget</span>.<span style="color: #0000cd;">__get__</span><span style="color: black;">&#40;</span><span style="color: #008000;">None</span>, owner<span style="color: black;">&#41;</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;">#&lt;sm&gt;</span>
<span style="color: #808080; font-style: italic;"># Encore un décorateur, cette fois sous forme de classe (on ne les a pas vu)</span>
<span style="color: #808080; font-style: italic;"># Celui-ci, quand il est appliqué, sert à ce qu'une méthode soit à la fois</span>
<span style="color: #808080; font-style: italic;"># une méthode d'instance et une méthode de classe, le choix se faisant</span>
<span style="color: #808080; font-style: italic;"># dynamiquement selon la situation.</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Par exemple dans:</span>
&nbsp;
<span style="color: #808080; font-style: italic;">#     @multimethod</span>
<span style="color: #808080; font-style: italic;">#     def joinpath(cls, first, *others):</span>
<span style="color: #808080; font-style: italic;">#         &quot;&quot;&quot;</span>
<span style="color: #808080; font-style: italic;">#         Join first to zero or more path components, adding a separator</span>
<span style="color: #808080; font-style: italic;">#         character (first.module.sep) if needed.  Returns a new instance of</span>
<span style="color: #808080; font-style: italic;">#         first._next_class.</span>
<span style="color: #808080; font-style: italic;">#         &quot;&quot;&quot;</span>
<span style="color: #808080; font-style: italic;">#         if not isinstance(first, cls):</span>
<span style="color: #808080; font-style: italic;">#             first = cls(first)</span>
<span style="color: #808080; font-style: italic;">#         return first._next_class(first.module.join(first, *others))</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># 'cls' sera une instance ou une classe selon que l'appel se fasse depuis la</span>
<span style="color: #808080; font-style: italic;"># classe ou l'instance.</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Notez le nom de la classe qui n'est pas en CamelCase (pas de majuscule)</span>
<span style="color: #808080; font-style: italic;"># alors qu'il s'agit bien d'un classe. Comme c'est un décorateur, on a</span>
<span style="color: #808080; font-style: italic;"># l'habitude de les voire en minuscule, donc on laisse ce nom en minuscule.</span>
<span style="color: #808080; font-style: italic;"># C'est une des rares exceptions au PEP8 (on en verra d'autres plus bas)</span>
<span style="color: #808080; font-style: italic;"># qu'on peut se permettre quand on sait ce qu'on fait :-)</span>
<span style="color: #808080; font-style: italic;">#&lt;/sm&gt;</span>
<span style="color: #ff7700;font-weight:bold;">class</span> multimethod<span style="color: black;">&#40;</span><span style="color: #008000;">object</span><span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot;
    Acts like a classmethod when invoked from the class and like an
    instancemethod when invoked from the instance.
    &quot;&quot;&quot;</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>, func<span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>.<span style="color: black;">func</span> = func
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__get__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, instance, owner<span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: black;">&#40;</span>
            functools.<span style="color: black;">partial</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">func</span>, owner<span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">if</span> instance <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #008000;">None</span>
            <span style="color: #ff7700;font-weight:bold;">else</span> functools.<span style="color: black;">partial</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">func</span>, owner, instance<span style="color: black;">&#41;</span>
        <span style="color: black;">&#41;</span>
&nbsp;
&nbsp;
<span style="color: #808080; font-style: italic;">#&lt;sm&gt;</span>
<span style="color: #808080; font-style: italic;"># La classe principale, et le plus gros morceau de code. Une classe peut</span>
<span style="color: #808080; font-style: italic;"># tout à fait faire plusieurs centaines de lignes.</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># En général je recommande de ne pas avoir de fichiers qui fait plus de 500</span>
<span style="color: #808080; font-style: italic;"># lignes en Python, mais ici le but est clairement de faire une lib qui tient</span>
<span style="color: #808080; font-style: italic;"># dans un fichier pour l'auteur.</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># La classe hérite du type unicode (hé oui, on peut hériter des types</span>
<span style="color: #808080; font-style: italic;"># built-in !); ainsi le path peut être manipulé comme une chaîne et reste</span>
<span style="color: #808080; font-style: italic;"># compatible avec tous les outils de manipulation de nom de fichiers existant</span>
<span style="color: #808080; font-style: italic;"># car ils utilisent les chaînes.</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># L'héritage est une techno qui sert donc aussi à conserver des compatibilités</span>
<span style="color: #808080; font-style: italic;"># et des comportements existant / attendus.</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Encore une fois le nom est en minuscule alors que c'est une classe, c'est une</span>
<span style="color: #808080; font-style: italic;"># autre exception : quand on créer un type de base, on le met en minuscule</span>
<span style="color: #808080; font-style: italic;"># car c'est ce que fait la lib standard (int(), str(), list(), datetime(),</span>
<span style="color: #808080; font-style: italic;"># unicode, etc, sont en fait des classes).</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># La docstring pourrait être meilleure.</span>
<span style="color: #808080; font-style: italic;">#&lt;/sm&gt;</span>
<span style="color: #ff7700;font-weight:bold;">class</span> path<span style="color: black;">&#40;</span><span style="color: #008000;">unicode</span><span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot; Represents a filesystem path.
&nbsp;
    For documentation on individual methods, consult their
    counterparts in os.path.
    &quot;&quot;&quot;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;">#&lt;sm&gt;</span>
    <span style="color: #808080; font-style: italic;"># Probablement mon désaccord principal avec cette lib, l'init vérifie</span>
    <span style="color: #808080; font-style: italic;"># qu'on lui passe bien une chaîne alors que j'aurais choisit le duck typing.</span>
    <span style="color: #808080; font-style: italic;">#&lt;/sm&gt;</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>, other<span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #008000;">isinstance</span><span style="color: black;">&#40;</span>other, <span style="color: #008000;">basestring</span><span style="color: black;">&#41;</span>:
            <span style="color: #ff7700;font-weight:bold;">raise</span> <span style="color: #008000;">TypeError</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;path must be a string&quot;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;">#&lt;sm&gt;</span>
    <span style="color: #808080; font-style: italic;"># L'auteur stocke la référence de os.path ici, et l'utilise partout à la</span>
    <span style="color: #808080; font-style: italic;"># place d'utiliser os.path directement. Cela permet de changer ce module à</span>
    <span style="color: #808080; font-style: italic;"># la volée, par exemple pour utiliser spécifiquement le module dédié à</span>
    <span style="color: #808080; font-style: italic;"># Windows ou à unix au lieu de celui choisit automatiquement.</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># C'est un exemple de pattern stratégie.</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Et non, la docstring n'a aucun effet. Ça pourrait être un comment.</span>
    <span style="color: #808080; font-style: italic;"># En revanche, comme spécifié en comment, certains outils comme sphinx</span>
    <span style="color: #808080; font-style: italic;"># prend les docstring en compte sur les variables.</span>
&nbsp;
    <span style="color: #808080; font-style: italic;">#&lt;/sm&gt;</span>
&nbsp;
    module = <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>
    <span style="color: #483d8b;">&quot;The path module to use for path operations.&quot;</span>
&nbsp;
&nbsp;
    <span style="color: #808080; font-style: italic;">#&lt;sm&gt;</span>
    <span style="color: #808080; font-style: italic;"># Une méthode retourne une classe path dont le module est</span>
    <span style="color: #808080; font-style: italic;"># celui passé en paramètre. Pratique si vous voulez</span>
    <span style="color: #808080; font-style: italic;"># utiliser un module de spécifique à un OS depuis un autre</span>
    <span style="color: #808080; font-style: italic;"># mais juste ponctuellement.</span>
    <span style="color: #808080; font-style: italic;"># Par exemple sous Windows, vous voulez traiter un chemin</span>
    <span style="color: #808080; font-style: italic;"># (mais un seul, le reste est sous Windows) Unix, vous</span>
    <span style="color: #808080; font-style: italic;"># pouvez faire :</span>
    <span style="color: #808080; font-style: italic;">#</span>
    <span style="color: #808080; font-style: italic;"># &gt;&gt;&gt; import posixpath</span>
    <span style="color: #808080; font-style: italic;"># &gt;&gt;&gt; p = path.using_module(posixpath)('/etc')</span>
    <span style="color: #808080; font-style: italic;"># &gt;&gt;&gt; print p</span>
    <span style="color: #808080; font-style: italic;"># /etc</span>
    <span style="color: #808080; font-style: italic;"># &gt;&gt;&gt; p</span>
    <span style="color: #808080; font-style: italic;"># path_posixpath(u'/etc')</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># ce qui crée un objet path() dont l'attribut 'module' est le module</span>
    <span style="color: #808080; font-style: italic;">#  posixpath. C'est une application concrète de l'injection de dépendance.</span>
&nbsp;
    <span style="color: #808080; font-style: italic;">#&lt;/sm&gt;</span>
    @<span style="color: #008000;">classmethod</span>
    @simple_cache
    <span style="color: #ff7700;font-weight:bold;">def</span> using_module<span style="color: black;">&#40;</span>cls, module<span style="color: black;">&#41;</span>:
        subclass_name = cls.__name__ + <span style="color: #483d8b;">'_'</span> + module.__name__
        bases = <span style="color: black;">&#40;</span>cls,<span style="color: black;">&#41;</span>
        ns = <span style="color: black;">&#123;</span><span style="color: #483d8b;">'module'</span>: module<span style="color: black;">&#125;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">type</span><span style="color: black;">&#40;</span>subclass_name, bases, ns<span style="color: black;">&#41;</span>
&nbsp;
&nbsp;
    <span style="color: #808080; font-style: italic;">#&lt;sm&gt;</span>
    <span style="color: #808080; font-style: italic;"># Une propriété qui retourne la classe (oui, on peut retourner une CLASSE)</span>
    <span style="color: #808080; font-style: italic;"># à utiliser si on veut créer une nouvelle instance de cette classe.</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># C'est très abstrait, vous n'aurez pas à faire ça tous les jours.</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># C'est une méthode placée là pour permettre un maximum de configurabilité</span>
    <span style="color: #808080; font-style: italic;"># : si vous changez cette classe, certaines méthodes renverront un autre</span>
    <span style="color: #808080; font-style: italic;"># type plutôt que le type en cours. Utile pour certains cas où vous voulez</span>
    <span style="color: #808080; font-style: italic;"># hériter de path() mais désirez un comportement spécial pour la création</span>
    <span style="color: #808080; font-style: italic;"># de nouveaux path.</span>
    <span style="color: #808080; font-style: italic;">#&lt;/sm&gt;</span>
    @ClassProperty
    @<span style="color: #008000;">classmethod</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> _next_class<span style="color: black;">&#40;</span>cls<span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">&quot;&quot;&quot;
        What class should be used to construct new instances from this class
        &quot;&quot;&quot;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> cls
&nbsp;
    <span style="color: #808080; font-style: italic;"># --- Special Python methods.</span>
&nbsp;
    <span style="color: #808080; font-style: italic;">#&lt;sm&gt;</span>
    <span style="color: #808080; font-style: italic;"># Là on attaque la définition de toutes les méthodes magiques.</span>
    <span style="color: #808080; font-style: italic;"># Essentiellement pour overrider le comportement par défaut des chaines</span>
    <span style="color: #808080; font-style: italic;"># unicode et exposer une API sympas.</span>
    <span style="color: #808080; font-style: italic;">#&lt;/sm&gt;</span>
&nbsp;
&nbsp;
    <span style="color: #808080; font-style: italic;">#&lt;sm&gt;</span>
    <span style="color: #808080; font-style: italic;"># Dans le shell, un path s'affichera path('chemin') et non 'chemin'</span>
    <span style="color: #808080; font-style: italic;"># L'auteur affiche en fait le nom du type en cours (en cas d'héritage</span>
    <span style="color: #808080; font-style: italic;"># cela changera) et ensuite la representation du parent, en l'occurence</span>
    <span style="color: #808080; font-style: italic;"># la classe unicode().</span>
    <span style="color: #808080; font-style: italic;">#&lt;/sm&gt;</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__repr__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #483d8b;">'%s(%s)'</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span><span style="color: #008000;">type</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>.__name__, <span style="color: #008000;">super</span><span style="color: black;">&#40;</span>path, <span style="color: #008000;">self</span><span style="color: black;">&#41;</span>.<span style="color: #0000cd;">__repr__</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
&nbsp;
    <span style="color: #808080; font-style: italic;">#&lt;sm&gt;</span>
    <span style="color: #808080; font-style: italic;"># Override l'addition.</span>
    <span style="color: #808080; font-style: italic;"># path('truc') + 'machin' donne path('trucmachin')</span>
    <span style="color: #808080; font-style: italic;">#&lt;/sm&gt;</span>
    <span style="color: #808080; font-style: italic;"># Adding a path and a string yields a path.</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>, more<span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">try</span>:
            <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>._next_class<span style="color: black;">&#40;</span><span style="color: #008000;">super</span><span style="color: black;">&#40;</span>path, <span style="color: #008000;">self</span><span style="color: black;">&#41;</span>.<span style="color: #0000cd;">__add__</span><span style="color: black;">&#40;</span>more<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">TypeError</span>:  <span style="color: #808080; font-style: italic;"># Python bug</span>
            <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">NotImplemented</span>
&nbsp;
    <span style="color: #808080; font-style: italic;">#&lt;sm&gt;</span>
    <span style="color: #808080; font-style: italic;"># 'machin' + path('truc') donne path('trucmachin')</span>
    <span style="color: #808080; font-style: italic;">#&lt;/sm&gt;</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__radd__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, other<span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #008000;">isinstance</span><span style="color: black;">&#40;</span>other, <span style="color: #008000;">basestring</span><span style="color: black;">&#41;</span>:
            <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">NotImplemented</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>._next_class<span style="color: black;">&#40;</span>other.<span style="color: #0000cd;">__add__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;">#&lt;sm&gt;</span>
    <span style="color: #808080; font-style: italic;"># Override la division.</span>
    <span style="color: #808080; font-style: italic;"># path('truc') / 'machin' donne path('trucm/achin')</span>
    <span style="color: #808080; font-style: italic;">#&lt;/sm&gt;</span>
    <span style="color: #808080; font-style: italic;"># The / operator joins paths.</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__div__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, rel<span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">&quot;&quot;&quot; fp.__div__(rel) == fp / rel == fp.joinpath(rel)
&nbsp;
        Join two path components, adding a separator character if
        needed.
        &quot;&quot;&quot;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>._next_class<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">module</span>.<span style="color: black;">join</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, rel<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;">#&lt;sm&gt;</span>
    <span style="color: #808080; font-style: italic;"># Petite astuce de compatibilité si le mec a fait</span>
    <span style="color: #808080; font-style: italic;"># from __future__ import division ou si on est en Python 3</span>
    <span style="color: #808080; font-style: italic;">#</span>
    <span style="color: #808080; font-style: italic;"># Remarque : on peut définir des attributs de classe n'importe où, et pas</span>
    <span style="color: #808080; font-style: italic;"># seulement en haut de la classe.</span>
    <span style="color: #808080; font-style: italic;">#&lt;/sm&gt;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Make the / operator work even when true division is enabled.</span>
    __truediv__ = <span style="color: #0000cd;">__div__</span>
&nbsp;
    <span style="color: #808080; font-style: italic;">#&lt;sm&gt;</span>
    <span style="color: #808080; font-style: italic;"># path() est aussi un context manager qu'on peut utiliser avec with !</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># with path('truc'):</span>
    <span style="color: #808080; font-style: italic;">#     tout ce qui est ici ce fait dans le dossier truc</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># *_ n'est pas une notation qui a un effet spécial. '_' est un nom de</span>
    <span style="color: #808080; font-style: italic;"># variable valide, c'est une convention pour dire 'je ne vais pas me</span>
    <span style="color: #808080; font-style: italic;"># servir de cet argument, je le déclare juste pour respecter la signature'</span>
    <span style="color: #808080; font-style: italic;"># et '*' et l'opérateur de paramétrage dynamique. '*_' est donc l'auteur</span>
    <span style="color: #808080; font-style: italic;"># signalant qu'il accepte n'importe quels paramètres positionnels, mais</span>
    <span style="color: #808080; font-style: italic;"># qu'ils ne les utilisera pas.</span>
    <span style="color: #808080; font-style: italic;">#&lt;/sm&gt;</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> __enter__<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>._old_dir = <span style="color: #008000;">self</span>.<span style="color: black;">getcwd</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        <span style="color: #dc143c;">os</span>.<span style="color: black;">chdir</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> __exit__<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, <span style="color: #66cc66;">*</span>_<span style="color: black;">&#41;</span>:
        <span style="color: #dc143c;">os</span>.<span style="color: black;">chdir</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>._old_dir<span style="color: black;">&#41;</span>
&nbsp;
&nbsp;
    <span style="color: #808080; font-style: italic;">#&lt;sm&gt;</span>
    <span style="color: #808080; font-style: italic;"># Le résultat de os.getcwdu(), mais retourne un objet path().</span>
    <span style="color: #808080; font-style: italic;"># Une bonne part du travail de la lib consiste à wrapper les méthodes</span>
    <span style="color: #808080; font-style: italic;"># ordinaires des autres modules pour qu'elles retournent un type path()</span>
    <span style="color: #808080; font-style: italic;"># pour qu'après on puisse faire des '.parent' ou utiliser '/' dessus</span>
    <span style="color: #808080; font-style: italic;"># sans y penser.</span>
    <span style="color: #808080; font-style: italic;">#&lt;/sm&gt;</span>
&nbsp;
    @<span style="color: #008000;">classmethod</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> getcwd<span style="color: black;">&#40;</span>cls<span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">&quot;&quot;&quot; Return the current working directory as a path object. &quot;&quot;&quot;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> cls<span style="color: black;">&#40;</span><span style="color: #dc143c;">os</span>.<span style="color: black;">getcwdu</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;">#</span>
    <span style="color: #808080; font-style: italic;"># --- Operations on path strings.</span>
&nbsp;
    <span style="color: #808080; font-style: italic;">#&lt;sm&gt;</span>
    <span style="color: #808080; font-style: italic;"># On enchaine ici des wrappers sur des méthodes de os.path (ou son</span>
    <span style="color: #808080; font-style: italic;"># remplaçant dans self.module), que l'objet s'applique à lui-même (self).</span>
    <span style="color: #808080; font-style: italic;"># Comme la classe hérite de 'unicode', toutes ces méthodes marchent.</span>
    <span style="color: #808080; font-style: italic;"># Et comme self._next_class retourne la classe pour créer le prochain</span>
    <span style="color: #808080; font-style: italic;"># path, on retourne toujours un objet de type 'path'.</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Si on fait fi des abstractions et qu'on lit les valeurs par défaut,</span>
&nbsp;
    <span style="color: #808080; font-style: italic;">#     self._next_class(self.module.abspath(self))</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># fait en fait:</span>
&nbsp;
    <span style="color: #808080; font-style: italic;">#     path(os.path.abspath('ton_chemin'))</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Ce qui donne l'API suivante quand on utilise la lib :</span>
&nbsp;
    <span style="color: #808080; font-style: italic;">#     &gt;&gt;&gt; path('/etc/nginx/..').abspath()</span>
    <span style="color: #808080; font-style: italic;">#     path(u'/etc')</span>
    <span style="color: #808080; font-style: italic;">#&lt;/sm&gt;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> abspath<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>._next_class<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">module</span>.<span style="color: black;">abspath</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> normcase<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>._next_class<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">module</span>.<span style="color: black;">normcase</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> normpath<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>._next_class<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">module</span>.<span style="color: black;">normpath</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> realpath<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>._next_class<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">module</span>.<span style="color: black;">realpath</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> expanduser<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>._next_class<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">module</span>.<span style="color: black;">expanduser</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> expandvars<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>._next_class<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">module</span>.<span style="color: black;">expandvars</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> dirname<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>._next_class<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">module</span>.<span style="color: black;">dirname</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> basename<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>._next_class<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">module</span>.<span style="color: black;">basename</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
&nbsp;
    <span style="color: #808080; font-style: italic;">#&lt;sm&gt;</span>
    <span style="color: #808080; font-style: italic;"># Là on rentre dans les méthodes utilitaires. L'auteur a constaté qu'on</span>
    <span style="color: #808080; font-style: italic;"># appelait très souvent ces trois méthodes sur les chemin des fichiers de</span>
    <span style="color: #808080; font-style: italic;"># config genre '~/toto' pour obtenir '/home/sam/toto' et propose donc</span>
    <span style="color: #808080; font-style: italic;"># un shortcut pour le faire car honnêtement, qui se souvient du nom</span>
    <span style="color: #808080; font-style: italic;"># de ces 3 méthodes à enchaîner pour obtenir un truc bullet proof ?</span>
    <span style="color: #808080; font-style: italic;"># Règle d'or d'une belle API : si il faut regarder dans la doc à chaque</span>
    <span style="color: #808080; font-style: italic;"># fois qu'on utilise quelque chose, il faut écrire un meilleur code.</span>
    <span style="color: #808080; font-style: italic;">#&lt;/sm&gt;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> expand<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">&quot;&quot;&quot; Clean up a filename by calling expandvars(),
        expanduser(), and normpath() on it.
&nbsp;
        This is commonly everything needed to clean up a filename
        read from a configuration file, for example.
        &quot;&quot;&quot;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>.<span style="color: black;">expandvars</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>.<span style="color: black;">expanduser</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>.<span style="color: black;">normpath</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
&nbsp;
    <span style="color: #808080; font-style: italic;">#&lt;sm&gt;</span>
    <span style="color: #808080; font-style: italic;"># Le méthodes suivantes sont préfixées d'un '_', donc elle n'apparaitrons</span>
    <span style="color: #808080; font-style: italic;"># pas dans les résultats d'outils avec complétion du code. Cela nous</span>
    <span style="color: #808080; font-style: italic;"># indique qu'il s'agit d'un détail implémentation, et que l'on ne devrait</span>
    <span style="color: #808080; font-style: italic;"># pas l'utiliser en dehors de la classe. Rien n'empêche de le faire</span>
    <span style="color: #808080; font-style: italic;"># cependant si vous avez envie de faire un beau hack bien gras.</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Ici l'auteur fait ce choix car il va enrober ces appels dans des</span>
    <span style="color: #808080; font-style: italic;"># propriétés pour les déguiser en attributs.</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Ce 3 méthodes retournent respectivement l'extension de fichier, le nom</span>
    <span style="color: #808080; font-style: italic;"># de fichier sans extension, et la lettre de lecteur sur les chemins</span>
    <span style="color: #808080; font-style: italic;"># windows.</span>
    <span style="color: #808080; font-style: italic;">#&lt;/sm&gt;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> _get_namebase<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        base, ext = <span style="color: #008000;">self</span>.<span style="color: black;">module</span>.<span style="color: black;">splitext</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">name</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> base
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> _get_ext<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        f, ext = <span style="color: #008000;">self</span>.<span style="color: black;">module</span>.<span style="color: black;">splitext</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> ext
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> _get_drive<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        drive, r = <span style="color: #008000;">self</span>.<span style="color: black;">module</span>.<span style="color: black;">splitdrive</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>._next_class<span style="color: black;">&#40;</span>drive<span style="color: black;">&#41;</span>
&nbsp;
&nbsp;
    <span style="color: #808080; font-style: italic;">#&lt;sm&gt;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Malgré l'indentation bizarre, il s'agit bien de :</span>
&nbsp;
    <span style="color: #808080; font-style: italic;">#     attribut_de_classe = function(arg1, arg2, arg3, arg4)</span>
&nbsp;
&nbsp;
    <span style="color: #808080; font-style: italic;"># Dans les tutos précédents vous avez vu comment créer une propriété avec</span>
    <span style="color: #808080; font-style: italic;"># le décorateur @property.</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Ici l'auteur utilise l'ancienne façon de faire, car il veut garder la</span>
    <span style="color: #808080; font-style: italic;"># compatibilité avec la python 2.5.</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># C'est globalement la même chose, par exemple ici l'attribut 'namebase'</span>
    <span style="color: #808080; font-style: italic;"># est défini comme une property et y accéder en lecture va appeler la</span>
    <span style="color: #808080; font-style: italic;"># méthode '_get_namebase'. Le second et le troisième argument de</span>
    <span style="color: #808080; font-style: italic;"># property() sont les setter et les deleter qui ne sont pas ici définis et</span>
    <span style="color: #808080; font-style: italic;"># mis à None (donc l'attribut est en lecture seule). Le dernier argument</span>
    <span style="color: #808080; font-style: italic;"># est la docstring.</span>
&nbsp;
    <span style="color: #808080; font-style: italic;">#&lt;/sm&gt;</span>
&nbsp;
    parent = <span style="color: #008000;">property</span><span style="color: black;">&#40;</span>
        dirname, <span style="color: #008000;">None</span>, <span style="color: #008000;">None</span>,
        <span style="color: #483d8b;">&quot;&quot;&quot; This path's parent directory, as a new path object.
&nbsp;
        For example, path('/usr/local/lib/libpython.so').parent == path('/usr/local/lib')
        &quot;&quot;&quot;</span><span style="color: black;">&#41;</span>
&nbsp;
    name = <span style="color: #008000;">property</span><span style="color: black;">&#40;</span>
        basename, <span style="color: #008000;">None</span>, <span style="color: #008000;">None</span>,
        <span style="color: #483d8b;">&quot;&quot;&quot; The name of this file or directory without the full path.
&nbsp;
        For example, path('/usr/local/lib/libpython.so').name == 'libpython.so'
        &quot;&quot;&quot;</span><span style="color: black;">&#41;</span>
&nbsp;
    namebase = <span style="color: #008000;">property</span><span style="color: black;">&#40;</span>
        _get_namebase, <span style="color: #008000;">None</span>, <span style="color: #008000;">None</span>,
        <span style="color: #483d8b;">&quot;&quot;&quot; The same as path.name, but with one file extension stripped off.
&nbsp;
        For example, path('/home/guido/python.tar.gz').name     == 'python.tar.gz',
        but          path('/home/guido/python.tar.gz').namebase == 'python.tar'
        &quot;&quot;&quot;</span><span style="color: black;">&#41;</span>
&nbsp;
    ext = <span style="color: #008000;">property</span><span style="color: black;">&#40;</span>
        _get_ext, <span style="color: #008000;">None</span>, <span style="color: #008000;">None</span>,
        <span style="color: #483d8b;">&quot;&quot;&quot; The file extension, for example '.py'. &quot;&quot;&quot;</span><span style="color: black;">&#41;</span>
&nbsp;
    drive = <span style="color: #008000;">property</span><span style="color: black;">&#40;</span>
        _get_drive, <span style="color: #008000;">None</span>, <span style="color: #008000;">None</span>,
        <span style="color: #483d8b;">&quot;&quot;&quot; The drive specifier, for example 'C:'.
        This is always empty on systems that don't use drive specifiers.
        &quot;&quot;&quot;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;">#&lt;sm&gt;</span>
    <span style="color: #808080; font-style: italic;"># Encore des wrappers pour retourner des objets path(). La structure</span>
    <span style="color: #808080; font-style: italic;"># est classique: définition de méthodes courtes avec docstring.</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># L'auteur retourne un tuple comme les méthodes originales (autant</span>
    <span style="color: #808080; font-style: italic;"># changer le comportement attendu le moins possible), mais cast la</span>
    <span style="color: #808080; font-style: italic;"># première partie du tuple en objet path().</span>
    <span style="color: #808080; font-style: italic;">#&lt;/sm&gt;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> splitpath<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">&quot;&quot;&quot; p.splitpath() -&gt; Return (p.parent, p.name). &quot;&quot;&quot;</span>
        parent, child = <span style="color: #008000;">self</span>.<span style="color: black;">module</span>.<span style="color: black;">split</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>._next_class<span style="color: black;">&#40;</span>parent<span style="color: black;">&#41;</span>, child
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> splitdrive<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">&quot;&quot;&quot; p.splitdrive() -&gt; Return (p.drive, &lt;the rest of p&gt;).
&nbsp;
        Split the drive specifier from this path.  If there is
        no drive specifier, p.drive is empty, so the return value
        is simply (path(''), p).  This is always the case on Unix.
        &quot;&quot;&quot;</span>
        drive, rel = <span style="color: #008000;">self</span>.<span style="color: black;">module</span>.<span style="color: black;">splitdrive</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>._next_class<span style="color: black;">&#40;</span>drive<span style="color: black;">&#41;</span>, rel
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> splitext<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">&quot;&quot;&quot; p.splitext() -&gt; Return (p.stripext(), p.ext).
&nbsp;
        Split the filename extension from this path and return
        the two parts.  Either part may be empty.
&nbsp;
        The extension is everything from '.' to the end of the
        last path segment.  This has the property that if
        (a, b) == p.splitext(), then a + b == p.
        &quot;&quot;&quot;</span>
        filename, ext = <span style="color: #008000;">self</span>.<span style="color: black;">module</span>.<span style="color: black;">splitext</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>._next_class<span style="color: black;">&#40;</span>filename<span style="color: black;">&#41;</span>, ext
&nbsp;
    <span style="color: #808080; font-style: italic;">#&lt;sm&gt;</span>
    <span style="color: #808080; font-style: italic;"># Ici on a des méthodes légèrement différentes de celles qu'elles wraps.</span>
    <span style="color: #808080; font-style: italic;"># C'est vraiment pour se faciliter la tâche sur les opérations courantes</span>
    <span style="color: #808080; font-style: italic;"># et sauver quelques caractères à la frappe.</span>
    <span style="color: #808080; font-style: italic;">#&lt;/sm&gt;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> stripext<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">&quot;&quot;&quot; p.stripext() -&gt; Remove one file extension from the path.
&nbsp;
        For example, path('/home/guido/python.tar.gz').stripext()
        returns path('/home/guido/python.tar').
        &quot;&quot;&quot;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>.<span style="color: black;">splitext</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> splitunc<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        unc, rest = <span style="color: #008000;">self</span>.<span style="color: black;">module</span>.<span style="color: black;">splitunc</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>._next_class<span style="color: black;">&#40;</span>unc<span style="color: black;">&#41;</span>, rest
&nbsp;
    @<span style="color: #008000;">property</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> uncshare<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">&quot;&quot;&quot;
        The UNC mount point for this path.
        This is empty for paths on local drives.
        &quot;&quot;&quot;</span>
        unc, r = <span style="color: #008000;">self</span>.<span style="color: black;">module</span>.<span style="color: black;">splitunc</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>._next_class<span style="color: black;">&#40;</span>unc<span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;">#&lt;sm&gt;</span>
    <span style="color: #808080; font-style: italic;"># joinpath cast le premier argument si il n'est pas du même type que la</span>
    <span style="color: #808080; font-style: italic;"># classe en cours. Il n'y a pas de raison apparente, donc je suppose que</span>
    <span style="color: #808080; font-style: italic;"># c'est pour éviter une bug qu'ils ont découvert dans une situation</span>
    <span style="color: #808080; font-style: italic;"># borderline</span>
    <span style="color: #808080; font-style: italic;">#&lt;/sm&gt;</span>
&nbsp;
    @multimethod
    <span style="color: #ff7700;font-weight:bold;">def</span> joinpath<span style="color: black;">&#40;</span>cls, first, <span style="color: #66cc66;">*</span>others<span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">&quot;&quot;&quot;
        Join first to zero or more path components, adding a separator
        character (first.module.sep) if needed.  Returns a new instance of
        first._next_class.
        &quot;&quot;&quot;</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #008000;">isinstance</span><span style="color: black;">&#40;</span>first, cls<span style="color: black;">&#41;</span>:
            first = cls<span style="color: black;">&#40;</span>first<span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> first._next_class<span style="color: black;">&#40;</span>first.<span style="color: black;">module</span>.<span style="color: black;">join</span><span style="color: black;">&#40;</span>first, <span style="color: #66cc66;">*</span>others<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
&nbsp;
    <span style="color: #808080; font-style: italic;">#&lt;sm&gt;</span>
    <span style="color: #808080; font-style: italic;"># Puis on arrive enfin dans les méthodes métiers qui ne sont pas dans les</span>
    <span style="color: #808080; font-style: italic;"># modules. Typiquement ce seront des méthodes plus longues et inconnues</span>
    <span style="color: #808080; font-style: italic;"># car n'existant pas dans les autres modules donc :</span>
    <span style="color: #808080; font-style: italic;"># - on les met à la fin</span>
    <span style="color: #808080; font-style: italic;"># - la docstring est plus explicite.</span>
    <span style="color: #808080; font-style: italic;"># Ici splitall permet de faire :</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># &gt;&gt;&gt; path('/usr/lib/python2.7/fnmatch.pyc').splitall()</span>
    <span style="color: #808080; font-style: italic;"># [path(u'/'), u'usr', u'lib', u'python2.7', u'fnmatch.pyc']</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Ce que os.path ne permet pas de faire directement.</span>
&nbsp;
    <span style="color: #808080; font-style: italic;">#&lt;/sm&gt;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> splitall<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        r<span style="color: #483d8b;">&quot;&quot;&quot; Return a list of the path components in this path.
&nbsp;
        The first item in the list will be a path.  Its value will be
        either os.curdir, os.pardir, empty, or the root directory of
        this path (for example, ``'/'`` or ``'C:<span style="color: #000099; font-weight: bold;">\\</span>'``).  The other items in
        the list will be strings.
&nbsp;
        ``path.path.joinpath(*result)`` will yield the original path.
        &quot;&quot;&quot;</span>
        parts = <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>
        loc = <span style="color: #008000;">self</span>
        <span style="color: #ff7700;font-weight:bold;">while</span> loc <span style="color: #66cc66;">!</span>= <span style="color: #dc143c;">os</span>.<span style="color: black;">curdir</span> <span style="color: #ff7700;font-weight:bold;">and</span> loc <span style="color: #66cc66;">!</span>= <span style="color: #dc143c;">os</span>.<span style="color: black;">pardir</span>:
            prev = loc
            loc, child = prev.<span style="color: black;">splitpath</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">if</span> loc == prev:
                <span style="color: #ff7700;font-weight:bold;">break</span>
            parts.<span style="color: black;">append</span><span style="color: black;">&#40;</span>child<span style="color: black;">&#41;</span>
        parts.<span style="color: black;">append</span><span style="color: black;">&#40;</span>loc<span style="color: black;">&#41;</span>
        parts.<span style="color: black;">reverse</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> parts
&nbsp;
&nbsp;
    <span style="color: #808080; font-style: italic;">#&lt;sm&gt;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Voici une bonne pratique, avoir une méthode complexe (ici relpathto(),</span>
    <span style="color: #808080; font-style: italic;"># qui créer un chemin relatif du path() courant vers un autre dossier), et</span>
    <span style="color: #808080; font-style: italic;"># son opposée plus simple (ici relpath(), qui créer un chemin relatif d'un</span>
    <span style="color: #808080; font-style: italic;"># dossier vers le path courant) qui utilise la méthode précédente en en</span>
    <span style="color: #808080; font-style: italic;"># inversant juste les paramètres.</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># En effet ça ne sert à rien d'écrire deux fois la même méthode, on</span>
    <span style="color: #808080; font-style: italic;"># factorise ainsi du code et respecte le principe DRY (don't repeat</span>
    <span style="color: #808080; font-style: italic;"># yourself).</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># relpathto() est un bon exemple d'un code assez complexe pour une</span>
    <span style="color: #808080; font-style: italic;"># opération qui parait pourtant assez simple. C'est aussi un très bon</span>
    <span style="color: #808080; font-style: italic;"># exemple de comment écrire des commentaires : on ne décrit pas les</span>
    <span style="color: #808080; font-style: italic;"># opérations évidentes mais on explique les choses ambiguës et on met des</span>
    <span style="color: #808080; font-style: italic;"># avertissements</span>
&nbsp;
    <span style="color: #808080; font-style: italic;">#&lt;/sm&gt;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> relpath<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, start=<span style="color: #483d8b;">'.'</span><span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">&quot;&quot;&quot; Return this path as a relative path,
        based from start, which defaults to the current working directory.
        &quot;&quot;&quot;</span>
        cwd = <span style="color: #008000;">self</span>._next_class<span style="color: black;">&#40;</span>start<span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> cwd.<span style="color: black;">relpathto</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> relpathto<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, dest<span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">&quot;&quot;&quot; Return a relative path from self to dest.
&nbsp;
        If there is no relative path from self to dest, for example if
        they reside on different drives in Windows, then this returns
        dest.abspath().
        &quot;&quot;&quot;</span>
        origin = <span style="color: #008000;">self</span>.<span style="color: black;">abspath</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        dest = <span style="color: #008000;">self</span>._next_class<span style="color: black;">&#40;</span>dest<span style="color: black;">&#41;</span>.<span style="color: black;">abspath</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
        orig_list = origin.<span style="color: black;">normcase</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>.<span style="color: black;">splitall</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        <span style="color: #808080; font-style: italic;"># Don't normcase dest!  We want to preserve the case.</span>
        dest_list = dest.<span style="color: black;">splitall</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
        <span style="color: #ff7700;font-weight:bold;">if</span> orig_list<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span> <span style="color: #66cc66;">!</span>= <span style="color: #008000;">self</span>.<span style="color: black;">module</span>.<span style="color: black;">normcase</span><span style="color: black;">&#40;</span>dest_list<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>:
            <span style="color: #808080; font-style: italic;"># Can't get here from there.</span>
            <span style="color: #ff7700;font-weight:bold;">return</span> dest
&nbsp;
        <span style="color: #808080; font-style: italic;"># Find the location where the two paths start to differ.</span>
        i = <span style="color: #ff4500;">0</span>
        <span style="color: #ff7700;font-weight:bold;">for</span> start_seg, dest_seg <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">zip</span><span style="color: black;">&#40;</span>orig_list, dest_list<span style="color: black;">&#41;</span>:
            <span style="color: #ff7700;font-weight:bold;">if</span> start_seg <span style="color: #66cc66;">!</span>= <span style="color: #008000;">self</span>.<span style="color: black;">module</span>.<span style="color: black;">normcase</span><span style="color: black;">&#40;</span>dest_seg<span style="color: black;">&#41;</span>:
                <span style="color: #ff7700;font-weight:bold;">break</span>
            i += <span style="color: #ff4500;">1</span>
&nbsp;
        <span style="color: #808080; font-style: italic;"># Now i is the point where the two paths diverge.</span>
        <span style="color: #808080; font-style: italic;"># Need a certain number of &quot;os.pardir&quot;s to work up</span>
        <span style="color: #808080; font-style: italic;"># from the origin to the point of divergence.</span>
        segments = <span style="color: black;">&#91;</span><span style="color: #dc143c;">os</span>.<span style="color: black;">pardir</span><span style="color: black;">&#93;</span> <span style="color: #66cc66;">*</span> <span style="color: black;">&#40;</span><span style="color: #008000;">len</span><span style="color: black;">&#40;</span>orig_list<span style="color: black;">&#41;</span> - i<span style="color: black;">&#41;</span>
        <span style="color: #808080; font-style: italic;"># Need to add the diverging part of dest_list.</span>
        segments += dest_list<span style="color: black;">&#91;</span>i:<span style="color: black;">&#93;</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>segments<span style="color: black;">&#41;</span> == <span style="color: #ff4500;">0</span>:
            <span style="color: #808080; font-style: italic;"># If they happen to be identical, use os.curdir.</span>
            relpath = <span style="color: #dc143c;">os</span>.<span style="color: black;">curdir</span>
        <span style="color: #ff7700;font-weight:bold;">else</span>:
            relpath = <span style="color: #008000;">self</span>.<span style="color: black;">module</span>.<span style="color: black;">join</span><span style="color: black;">&#40;</span><span style="color: #66cc66;">*</span>segments<span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>._next_class<span style="color: black;">&#40;</span>relpath<span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># --- Listing, searching, walking, and matching</span>
&nbsp;
    <span style="color: #808080; font-style: italic;">#&lt;sm&gt;</span>
    <span style="color: #808080; font-style: italic;"># un simple wrapper mais qui rajoute un argument en plus : un pattern à la</span>
    <span style="color: #808080; font-style: italic;"># unix. C'est une extension naturelle, et c'est le genre de chose que vous</span>
    <span style="color: #808080; font-style: italic;"># voudrez faire quand vous vous êtes toujours demandé : &quot;mais pourquoi</span>
    <span style="color: #808080; font-style: italic;"># c'est pas par défaut ?&quot; ou &quot;comment on fait ça facilement ?&quot; Si vous</span>
    <span style="color: #808080; font-style: italic;"># vous posez ce genre de question, étendez un peu les comportements</span>
    <span style="color: #808080; font-style: italic;"># initiaux. Rajouter un argument ne rend pas le comportement différent du</span>
    <span style="color: #808080; font-style: italic;"># précédent grâce au paramètre par défaut mis à None, donc c'est tout</span>
    <span style="color: #808080; font-style: italic;"># bénef.</span>
    <span style="color: #808080; font-style: italic;">#&lt;/sm&gt;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> listdir<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, pattern=<span style="color: #008000;">None</span><span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">&quot;&quot;&quot; D.listdir() -&gt; List of items in this directory.
&nbsp;
        Use D.files() or D.dirs() instead if you want a listing
        of just files or just subdirectories.
&nbsp;
        The elements of the list are path objects.
&nbsp;
        With the optional 'pattern' argument, this only lists
        items whose names match the given pattern.
        &quot;&quot;&quot;</span>
        names = <span style="color: #dc143c;">os</span>.<span style="color: black;">listdir</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> pattern <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #008000;">None</span>:
            names = <span style="color: #dc143c;">fnmatch</span>.<span style="color: #008000;">filter</span><span style="color: black;">&#40;</span>names, pattern<span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: black;">&#91;</span><span style="color: #008000;">self</span> / child <span style="color: #ff7700;font-weight:bold;">for</span> child <span style="color: #ff7700;font-weight:bold;">in</span> names<span style="color: black;">&#93;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;">#&lt;sm&gt;</span>
    <span style="color: #808080; font-style: italic;"># Dans la même lignée de ce qu'on a vu plus haut: utiliser une fonction</span>
    <span style="color: #808080; font-style: italic;"># plus complexe (qui déjà étend un comportement par défaut) pour en</span>
    <span style="color: #808080; font-style: italic;"># faire encore une méthode plus spécialisée.</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># L'avantage de cette approche c'est que le code est plein de petites</span>
    <span style="color: #808080; font-style: italic;"># briques:</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># vous avez listdir(), qui est assez court (mais déjà plus puissant),</span>
    <span style="color: #808080; font-style: italic;"># puis dirs() et files(), qui font la même chose en plus spécialisés.</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># L'alternative aurait été d'ajouter une param à listdir() et ne pas</span>
    <span style="color: #808080; font-style: italic;"># créer dirs() et files(), mais ça aurait rajouté un if dans le code et</span>
    <span style="color: #808080; font-style: italic;"># un paramètre qui fait rechercher dans la doc celui qui l'utilise et</span>
    <span style="color: #808080; font-style: italic;"># celui qui lit le code.</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Avec l'approche actuelle, l'API est très claire :</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># for d in path('/etc').dirs()</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># On s'attend à lire tous les dossiers de /etc. Et les</span>
    <span style="color: #808080; font-style: italic;"># méthodes restent courtes.</span>
&nbsp;
    <span style="color: #808080; font-style: italic;">#&lt;/sm&gt;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> dirs<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, pattern=<span style="color: #008000;">None</span><span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">&quot;&quot;&quot; D.dirs() -&gt; List of this directory's subdirectories.
&nbsp;
        The elements of the list are path objects.
        This does not walk recursively into subdirectories
        (but see path.walkdirs).
&nbsp;
        With the optional 'pattern' argument, this only lists
        directories whose names match the given pattern.  For
        example, ``d.dirs('build-*')``.
        &quot;&quot;&quot;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: black;">&#91;</span>p <span style="color: #ff7700;font-weight:bold;">for</span> p <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">self</span>.<span style="color: black;">listdir</span><span style="color: black;">&#40;</span>pattern<span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">if</span> p.<span style="color: black;">isdir</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> files<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, pattern=<span style="color: #008000;">None</span><span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">&quot;&quot;&quot; D.files() -&gt; List of the files in this directory.
&nbsp;
        The elements of the list are path objects.
        This does not walk into subdirectories (see path.walkfiles).
&nbsp;
        With the optional 'pattern' argument, this only lists files
        whose names match the given pattern.  For example,
        ``d.files('*.pyc')``.
        &quot;&quot;&quot;</span>
&nbsp;
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: black;">&#91;</span>p <span style="color: #ff7700;font-weight:bold;">for</span> p <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">self</span>.<span style="color: black;">listdir</span><span style="color: black;">&#40;</span>pattern<span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">if</span> p.<span style="color: black;">isfile</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span>
&nbsp;
&nbsp;
    <span style="color: #808080; font-style: italic;">#&lt;sm&gt;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># walk() et ses pendants walkdirs() et walkfiles() sont des alternatives</span>
    <span style="color: #808080; font-style: italic;"># au très peu intuitif os.path.walk qui permet de traverser récursivement</span>
    <span style="color: #808080; font-style: italic;"># un répertoire.</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># En effet, en Python les callbacks sont quelque chose qu'on utilise peu,</span>
    <span style="color: #808080; font-style: italic;"># et à l'inverse, on itère beaucoup.</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Cela permet de faire:</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># for f in path('/etc').walk_files():</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Pour lister récursivements tous les fichiers de /etc et de ses sous</span>
    <span style="color: #808080; font-style: italic;"># (et sous, sous, sous) dossiers.</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># C'est clair, c'est simple à comprendre et facile à utiliser.</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># L'auteur utilise ici 'yield', et c'est l'outil parfait pour cela.</span>
    <span style="color: #808080; font-style: italic;"># Souvenez vous de 'yield' comme un très bon moyen de parcourir des choses</span>
    <span style="color: #808080; font-style: italic;"># imbriquées comme si c'était une structure plate à une dimension.</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Yield permet de transformer n'importe quelle méthode d'un objet en</span>
    <span style="color: #808080; font-style: italic;"># un générateur sur un algorythme qui peut être très complexe, simplifiant</span>
    <span style="color: #808080; font-style: italic;"># son utilisation. Pensez-y !</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Sous le capot, c'est presque un appel récursif, si ce n'est qu'un nouvel</span>
    <span style="color: #808080; font-style: italic;"># objet path() est créé à chaque fois, depuis lequel on fait walk().</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Notez également que sur une méthode comme ça qui peut foirer facilement</span>
    <span style="color: #808080; font-style: italic;"># (une opération sur des centaines de fichiers...), un paramètre permet</span>
    <span style="color: #808080; font-style: italic;"># de choisir une gestion des erreurs parmis :</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># - lever une exception (qui est dans un code propre le choix par défaut)</span>
    <span style="color: #808080; font-style: italic;"># - ignorer (pour faire un code tolérant aux erreur)</span>
    <span style="color: #808080; font-style: italic;"># - ou faire un retour sans erreur, mais avec un warning technique (utile</span>
    <span style="color: #808080; font-style: italic;">#     pour le scripting)</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Encore une fois, faire une classe, c'est l'occasion de penser à</span>
    <span style="color: #808080; font-style: italic;"># l'utilisateur de la classe, ce qui a été ici bien fait.</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Enfin, contrairement à ce qu'on pourrait attendre, walkdirs et walkfiles</span>
    <span style="color: #808080; font-style: italic;"># n'utilise pas walk(), ce qui est généralement fait pour des raisons de</span>
    <span style="color: #808080; font-style: italic;"># performances (on sacrifie le DRY pour éviter un appel de callback</span>
    <span style="color: #808080; font-style: italic;"># ou un test sur des grosses boucles), même si ici c'est une supposition.</span>
&nbsp;
    <span style="color: #808080; font-style: italic;">#&lt;/sm&gt;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> walk<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, pattern=<span style="color: #008000;">None</span>, errors=<span style="color: #483d8b;">'strict'</span><span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">&quot;&quot;&quot; D.walk() -&gt; iterator over files and subdirs, recursively.
&nbsp;
        The iterator yields path objects naming each child item of
        this directory and its descendants.  This requires that
        D.isdir().
&nbsp;
        This performs a depth-first traversal of the directory tree.
        Each directory is returned just before all its children.
&nbsp;
        The errors= keyword argument controls behavior when an
        error occurs.  The default is 'strict', which causes an
        exception.  The other allowed values are 'warn', which
        reports the error via warnings.warn(), and 'ignore'.
        &quot;&quot;&quot;</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> errors <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: black;">&#40;</span><span style="color: #483d8b;">'strict'</span>, <span style="color: #483d8b;">'warn'</span>, <span style="color: #483d8b;">'ignore'</span><span style="color: black;">&#41;</span>:
            <span style="color: #ff7700;font-weight:bold;">raise</span> <span style="color: #008000;">ValueError</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;invalid errors parameter&quot;</span><span style="color: black;">&#41;</span>
&nbsp;
        <span style="color: #ff7700;font-weight:bold;">try</span>:
            childList = <span style="color: #008000;">self</span>.<span style="color: black;">listdir</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">Exception</span>:
            <span style="color: #ff7700;font-weight:bold;">if</span> errors == <span style="color: #483d8b;">'ignore'</span>:
                <span style="color: #ff7700;font-weight:bold;">return</span>
            <span style="color: #ff7700;font-weight:bold;">elif</span> errors == <span style="color: #483d8b;">'warn'</span>:
                <span style="color: #dc143c;">warnings</span>.<span style="color: black;">warn</span><span style="color: black;">&#40;</span>
                    <span style="color: #483d8b;">&quot;Unable to list directory '%s': %s&quot;</span>
                    <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, <span style="color: #dc143c;">sys</span>.<span style="color: black;">exc_info</span><span style="color: black;">&#40;</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: black;">&#41;</span>,
                    TreeWalkWarning<span style="color: black;">&#41;</span>
                <span style="color: #ff7700;font-weight:bold;">return</span>
            <span style="color: #ff7700;font-weight:bold;">else</span>:
                <span style="color: #ff7700;font-weight:bold;">raise</span>
&nbsp;
        <span style="color: #ff7700;font-weight:bold;">for</span> child <span style="color: #ff7700;font-weight:bold;">in</span> childList:
            <span style="color: #ff7700;font-weight:bold;">if</span> pattern <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #008000;">None</span> <span style="color: #ff7700;font-weight:bold;">or</span> child.<span style="color: #dc143c;">fnmatch</span><span style="color: black;">&#40;</span>pattern<span style="color: black;">&#41;</span>:
                <span style="color: #ff7700;font-weight:bold;">yield</span> child
            <span style="color: #ff7700;font-weight:bold;">try</span>:
                isdir = child.<span style="color: black;">isdir</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">Exception</span>:
                <span style="color: #ff7700;font-weight:bold;">if</span> errors == <span style="color: #483d8b;">'ignore'</span>:
                    isdir = <span style="color: #008000;">False</span>
                <span style="color: #ff7700;font-weight:bold;">elif</span> errors == <span style="color: #483d8b;">'warn'</span>:
                    <span style="color: #dc143c;">warnings</span>.<span style="color: black;">warn</span><span style="color: black;">&#40;</span>
                        <span style="color: #483d8b;">&quot;Unable to access '%s': %s&quot;</span>
                        <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span>child, <span style="color: #dc143c;">sys</span>.<span style="color: black;">exc_info</span><span style="color: black;">&#40;</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: black;">&#41;</span>,
                        TreeWalkWarning<span style="color: black;">&#41;</span>
                    isdir = <span style="color: #008000;">False</span>
                <span style="color: #ff7700;font-weight:bold;">else</span>:
                    <span style="color: #ff7700;font-weight:bold;">raise</span>
&nbsp;
            <span style="color: #ff7700;font-weight:bold;">if</span> isdir:
                <span style="color: #ff7700;font-weight:bold;">for</span> item <span style="color: #ff7700;font-weight:bold;">in</span> child.<span style="color: black;">walk</span><span style="color: black;">&#40;</span>pattern, errors<span style="color: black;">&#41;</span>:
                    <span style="color: #ff7700;font-weight:bold;">yield</span> item
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> walkdirs<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, pattern=<span style="color: #008000;">None</span>, errors=<span style="color: #483d8b;">'strict'</span><span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">&quot;&quot;&quot; D.walkdirs() -&gt; iterator over subdirs, recursively.
&nbsp;
        With the optional 'pattern' argument, this yields only
        directories whose names match the given pattern.  For
        example, ``mydir.walkdirs('*test')`` yields only directories
        with names ending in 'test'.
&nbsp;
        The errors= keyword argument controls behavior when an
        error occurs.  The default is 'strict', which causes an
        exception.  The other allowed values are 'warn', which
        reports the error via warnings.warn(), and 'ignore'.
        &quot;&quot;&quot;</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> errors <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: black;">&#40;</span><span style="color: #483d8b;">'strict'</span>, <span style="color: #483d8b;">'warn'</span>, <span style="color: #483d8b;">'ignore'</span><span style="color: black;">&#41;</span>:
            <span style="color: #ff7700;font-weight:bold;">raise</span> <span style="color: #008000;">ValueError</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;invalid errors parameter&quot;</span><span style="color: black;">&#41;</span>
&nbsp;
        <span style="color: #ff7700;font-weight:bold;">try</span>:
            dirs = <span style="color: #008000;">self</span>.<span style="color: black;">dirs</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">Exception</span>:
            <span style="color: #ff7700;font-weight:bold;">if</span> errors == <span style="color: #483d8b;">'ignore'</span>:
                <span style="color: #ff7700;font-weight:bold;">return</span>
            <span style="color: #ff7700;font-weight:bold;">elif</span> errors == <span style="color: #483d8b;">'warn'</span>:
                <span style="color: #dc143c;">warnings</span>.<span style="color: black;">warn</span><span style="color: black;">&#40;</span>
                    <span style="color: #483d8b;">&quot;Unable to list directory '%s': %s&quot;</span>
                    <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, <span style="color: #dc143c;">sys</span>.<span style="color: black;">exc_info</span><span style="color: black;">&#40;</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: black;">&#41;</span>,
                    TreeWalkWarning<span style="color: black;">&#41;</span>
                <span style="color: #ff7700;font-weight:bold;">return</span>
            <span style="color: #ff7700;font-weight:bold;">else</span>:
                <span style="color: #ff7700;font-weight:bold;">raise</span>
&nbsp;
        <span style="color: #ff7700;font-weight:bold;">for</span> child <span style="color: #ff7700;font-weight:bold;">in</span> dirs:
            <span style="color: #ff7700;font-weight:bold;">if</span> pattern <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #008000;">None</span> <span style="color: #ff7700;font-weight:bold;">or</span> child.<span style="color: #dc143c;">fnmatch</span><span style="color: black;">&#40;</span>pattern<span style="color: black;">&#41;</span>:
                <span style="color: #ff7700;font-weight:bold;">yield</span> child
            <span style="color: #ff7700;font-weight:bold;">for</span> subsubdir <span style="color: #ff7700;font-weight:bold;">in</span> child.<span style="color: black;">walkdirs</span><span style="color: black;">&#40;</span>pattern, errors<span style="color: black;">&#41;</span>:
                <span style="color: #ff7700;font-weight:bold;">yield</span> subsubdir
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> walkfiles<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, pattern=<span style="color: #008000;">None</span>, errors=<span style="color: #483d8b;">'strict'</span><span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">&quot;&quot;&quot; D.walkfiles() -&gt; iterator over files in D, recursively.
&nbsp;
        The optional argument, pattern, limits the results to files
        with names that match the pattern.  For example,
        ``mydir.walkfiles('*.tmp')`` yields only files with the .tmp
        extension.
        &quot;&quot;&quot;</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> errors <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: black;">&#40;</span><span style="color: #483d8b;">'strict'</span>, <span style="color: #483d8b;">'warn'</span>, <span style="color: #483d8b;">'ignore'</span><span style="color: black;">&#41;</span>:
            <span style="color: #ff7700;font-weight:bold;">raise</span> <span style="color: #008000;">ValueError</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;invalid errors parameter&quot;</span><span style="color: black;">&#41;</span>
&nbsp;
        <span style="color: #ff7700;font-weight:bold;">try</span>:
            childList = <span style="color: #008000;">self</span>.<span style="color: black;">listdir</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">Exception</span>:
            <span style="color: #ff7700;font-weight:bold;">if</span> errors == <span style="color: #483d8b;">'ignore'</span>:
                <span style="color: #ff7700;font-weight:bold;">return</span>
            <span style="color: #ff7700;font-weight:bold;">elif</span> errors == <span style="color: #483d8b;">'warn'</span>:
                <span style="color: #dc143c;">warnings</span>.<span style="color: black;">warn</span><span style="color: black;">&#40;</span>
                    <span style="color: #483d8b;">&quot;Unable to list directory '%s': %s&quot;</span>
                    <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, <span style="color: #dc143c;">sys</span>.<span style="color: black;">exc_info</span><span style="color: black;">&#40;</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: black;">&#41;</span>,
                    TreeWalkWarning<span style="color: black;">&#41;</span>
                <span style="color: #ff7700;font-weight:bold;">return</span>
            <span style="color: #ff7700;font-weight:bold;">else</span>:
                <span style="color: #ff7700;font-weight:bold;">raise</span>
&nbsp;
        <span style="color: #ff7700;font-weight:bold;">for</span> child <span style="color: #ff7700;font-weight:bold;">in</span> childList:
            <span style="color: #ff7700;font-weight:bold;">try</span>:
                isfile = child.<span style="color: black;">isfile</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
                isdir = <span style="color: #ff7700;font-weight:bold;">not</span> isfile <span style="color: #ff7700;font-weight:bold;">and</span> child.<span style="color: black;">isdir</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">except</span>:
                <span style="color: #ff7700;font-weight:bold;">if</span> errors == <span style="color: #483d8b;">'ignore'</span>:
                    <span style="color: #ff7700;font-weight:bold;">continue</span>
                <span style="color: #ff7700;font-weight:bold;">elif</span> errors == <span style="color: #483d8b;">'warn'</span>:
                    <span style="color: #dc143c;">warnings</span>.<span style="color: black;">warn</span><span style="color: black;">&#40;</span>
                        <span style="color: #483d8b;">&quot;Unable to access '%s': %s&quot;</span>
                        <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, <span style="color: #dc143c;">sys</span>.<span style="color: black;">exc_info</span><span style="color: black;">&#40;</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: black;">&#41;</span>,
                        TreeWalkWarning<span style="color: black;">&#41;</span>
                    <span style="color: #ff7700;font-weight:bold;">continue</span>
                <span style="color: #ff7700;font-weight:bold;">else</span>:
                    <span style="color: #ff7700;font-weight:bold;">raise</span>
&nbsp;
            <span style="color: #ff7700;font-weight:bold;">if</span> isfile:
                <span style="color: #ff7700;font-weight:bold;">if</span> pattern <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #008000;">None</span> <span style="color: #ff7700;font-weight:bold;">or</span> child.<span style="color: #dc143c;">fnmatch</span><span style="color: black;">&#40;</span>pattern<span style="color: black;">&#41;</span>:
                    <span style="color: #ff7700;font-weight:bold;">yield</span> child
            <span style="color: #ff7700;font-weight:bold;">elif</span> isdir:
                <span style="color: #ff7700;font-weight:bold;">for</span> f <span style="color: #ff7700;font-weight:bold;">in</span> child.<span style="color: black;">walkfiles</span><span style="color: black;">&#40;</span>pattern, errors<span style="color: black;">&#41;</span>:
                    <span style="color: #ff7700;font-weight:bold;">yield</span> f
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #dc143c;">fnmatch</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, pattern<span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">&quot;&quot;&quot; Return True if self.name matches the given pattern.
&nbsp;
        pattern - A filename pattern with wildcards,
            for example ``'*.py'``.
        &quot;&quot;&quot;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #dc143c;">fnmatch</span>.<span style="color: #dc143c;">fnmatch</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">name</span>, pattern<span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #dc143c;">glob</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, pattern<span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">&quot;&quot;&quot; Return a list of path objects that match the pattern.
&nbsp;
        pattern - a path relative to this directory, with wildcards.
&nbsp;
        For example, path('/users').glob('*/bin/*') returns a list
        of all the files users have in their bin directories.
        &quot;&quot;&quot;</span>
        cls = <span style="color: #008000;">self</span>._next_class
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: black;">&#91;</span>cls<span style="color: black;">&#40;</span>s<span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">for</span> s <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #dc143c;">glob</span>.<span style="color: #dc143c;">glob</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span> / pattern<span style="color: black;">&#41;</span><span style="color: black;">&#93;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;">#</span>
    <span style="color: #808080; font-style: italic;"># --- Reading or writing an entire file at once.</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #008000;">open</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, mode=<span style="color: #483d8b;">'r'</span><span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">&quot;&quot;&quot; Open this file.  Return a file object. &quot;&quot;&quot;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">open</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, mode<span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;">#&lt;sm&gt;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># L'avantage d'avoir une classe comme point de départ de tout c'est que</span>
    <span style="color: #808080; font-style: italic;"># c'est facile à manipuler dans le shell, surtout en autocompletion.</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Donc il est bon de mettre quelques outils qui sont pratiques dans les</span>
    <span style="color: #808080; font-style: italic;"># usages type shell.</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Ici c'est exactement le cas : on fait des méthodes un peu bourrines (</span>
    <span style="color: #808080; font-style: italic;"># globalement ça dump en mémoire ou ça écrit tout le fichier d'un coup),</span>
    <span style="color: #808080; font-style: italic;"># mais très pratiques pour manipuler les objets dans un terminal.</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Notez aussi le nettoyage opéré:</span>
&nbsp;
    <span style="color: #808080; font-style: italic;">#             return (t.replace(u'\r\n', u'\n')</span>
    <span style="color: #808080; font-style: italic;">#                  .replace(u'\r\x85', u'\n')</span>
    <span style="color: #808080; font-style: italic;">#                  .replace(u'\r', u'\n')</span>
    <span style="color: #808080; font-style: italic;">#                  .replace(u'\x85', u'\n')</span>
    <span style="color: #808080; font-style: italic;">#                  .replace(u'\u2028', u'\n'))</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Ce n'est pas particulièrement lié à la POO, mais l'encapsulation de</span>
    <span style="color: #808080; font-style: italic;"># ce genre de process est toujours le bienvenu. L'idée est que l'objet</span>
    <span style="color: #808080; font-style: italic;"># puisse être utilisé comme une boîte noire en laquelle on a totalement</span>
    <span style="color: #808080; font-style: italic;"># confiance.</span>
&nbsp;
    <span style="color: #808080; font-style: italic;">#&lt;/sm&gt;</span>
&nbsp;
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #dc143c;">bytes</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">&quot;&quot;&quot; Open this file, read all bytes, return them as a string. &quot;&quot;&quot;</span>
        <span style="color: #ff7700;font-weight:bold;">with</span> <span style="color: #008000;">self</span>.<span style="color: #008000;">open</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'rb'</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">as</span> f:
            <span style="color: #ff7700;font-weight:bold;">return</span> f.<span style="color: black;">read</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> write_bytes<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, <span style="color: #dc143c;">bytes</span>, append=<span style="color: #008000;">False</span><span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">&quot;&quot;&quot; Open this file and write the given bytes to it.
&nbsp;
        Default behavior is to overwrite any existing file.
        Call p.write_bytes(bytes, append=True) to append instead.
        &quot;&quot;&quot;</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> append:
            mode = <span style="color: #483d8b;">'ab'</span>
        <span style="color: #ff7700;font-weight:bold;">else</span>:
            mode = <span style="color: #483d8b;">'wb'</span>
        <span style="color: #ff7700;font-weight:bold;">with</span> <span style="color: #008000;">self</span>.<span style="color: #008000;">open</span><span style="color: black;">&#40;</span>mode<span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">as</span> f:
            f.<span style="color: black;">write</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">bytes</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> text<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, encoding=<span style="color: #008000;">None</span>, errors=<span style="color: #483d8b;">'strict'</span><span style="color: black;">&#41;</span>:
        r<span style="color: #483d8b;">&quot;&quot;&quot; Open this file, read it in, return the content as a string.
&nbsp;
        This method uses 'U' mode, so '<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>' and '<span style="color: #000099; font-weight: bold;">\r</span>' are automatically
        translated to '<span style="color: #000099; font-weight: bold;">\n</span>'.
&nbsp;
        Optional arguments:
&nbsp;
        encoding - The Unicode encoding (or character set) of
            the file.  If present, the content of the file is
            decoded and returned as a unicode object; otherwise
            it is returned as an 8-bit str.
        errors - How to handle Unicode errors; see help(str.decode)
            for the options.  Default is 'strict'.
        &quot;&quot;&quot;</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> encoding <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #008000;">None</span>:
            <span style="color: #808080; font-style: italic;"># 8-bit</span>
            <span style="color: #ff7700;font-weight:bold;">with</span> <span style="color: #008000;">self</span>.<span style="color: #008000;">open</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'U'</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">as</span> f:
                <span style="color: #ff7700;font-weight:bold;">return</span> f.<span style="color: black;">read</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">else</span>:
            <span style="color: #808080; font-style: italic;"># Unicode</span>
            <span style="color: #ff7700;font-weight:bold;">with</span> <span style="color: #dc143c;">codecs</span>.<span style="color: #008000;">open</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, <span style="color: #483d8b;">'r'</span>, encoding, errors<span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">as</span> f:
                <span style="color: #808080; font-style: italic;"># (Note - Can't use 'U' mode here, since codecs.open</span>
                <span style="color: #808080; font-style: italic;"># doesn't support 'U' mode.)</span>
                t = f.<span style="color: black;">read</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: black;">&#40;</span>t.<span style="color: black;">replace</span><span style="color: black;">&#40;</span>u<span style="color: #483d8b;">'<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>'</span>, u<span style="color: #483d8b;">'<span style="color: #000099; font-weight: bold;">\n</span>'</span><span style="color: black;">&#41;</span>
                     .<span style="color: black;">replace</span><span style="color: black;">&#40;</span>u<span style="color: #483d8b;">'<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\x</span>85'</span>, u<span style="color: #483d8b;">'<span style="color: #000099; font-weight: bold;">\n</span>'</span><span style="color: black;">&#41;</span>
                     .<span style="color: black;">replace</span><span style="color: black;">&#40;</span>u<span style="color: #483d8b;">'<span style="color: #000099; font-weight: bold;">\r</span>'</span>, u<span style="color: #483d8b;">'<span style="color: #000099; font-weight: bold;">\n</span>'</span><span style="color: black;">&#41;</span>
                     .<span style="color: black;">replace</span><span style="color: black;">&#40;</span>u<span style="color: #483d8b;">'<span style="color: #000099; font-weight: bold;">\x</span>85'</span>, u<span style="color: #483d8b;">'<span style="color: #000099; font-weight: bold;">\n</span>'</span><span style="color: black;">&#41;</span>
                     .<span style="color: black;">replace</span><span style="color: black;">&#40;</span>u<span style="color: #483d8b;">'<span style="color: #000099; font-weight: bold;">\u</span>2028'</span>, u<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>
&nbsp;
    <span style="color: #808080; font-style: italic;">#&lt;sm&gt;</span>
    <span style="color: #808080; font-style: italic;"># Sur des methodes avec de nombreux paramètres, ne pas hésiter</span>
    <span style="color: #808080; font-style: italic;"># à mettre un maximum de valeurs par défaut &quot;saines&quot; (c'est à dire la</span>
    <span style="color: #808080; font-style: italic;"># valeur du cas le plus courant ou pragmatique).</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Comme c'est une grosse fonction très configurable, la docstring</span>
    <span style="color: #808080; font-style: italic;"># est écrite en conséquence. Ne soyez pas timide avec la dosctring,</span>
    <span style="color: #808080; font-style: italic;"># on peut la faire très très très longue, ce n'est pas une mauvaise</span>
    <span style="color: #808080; font-style: italic;"># chose.</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Notez que la docstring est préfixée d'un &quot;r&quot; ici, pour que Python</span>
    <span style="color: #808080; font-style: italic;"># n'interprète pas les \n et \r.</span>
    <span style="color: #808080; font-style: italic;">#&lt;/sm&gt;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> write_text<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, text, encoding=<span style="color: #008000;">None</span>, errors=<span style="color: #483d8b;">'strict'</span>, linesep=<span style="color: #dc143c;">os</span>.<span style="color: black;">linesep</span>, append=<span style="color: #008000;">False</span><span style="color: black;">&#41;</span>:
        r<span style="color: #483d8b;">&quot;&quot;&quot; Write the given text to this file.
&nbsp;
        The default behavior is to overwrite any existing file;
        to append instead, use the 'append=True' keyword argument.
&nbsp;
        There are two differences between path.write_text() and
        path.write_bytes(): newline handling and Unicode handling.
        See below.
&nbsp;
        Parameters:
&nbsp;
          - text - str/unicode - The text to be written.
&nbsp;
          - encoding - str - The Unicode encoding that will be used.
            This is ignored if 'text' isn't a Unicode string.
&nbsp;
          - errors - str - How to handle Unicode encoding errors.
            Default is 'strict'.  See help(unicode.encode) for the
            options.  This is ignored if 'text' isn't a Unicode
            string.
&nbsp;
          - linesep - keyword argument - str/unicode - The sequence of
            characters to be used to mark end-of-line.  The default is
            os.linesep.  You can also specify None; this means to
            leave all newlines as they are in 'text'.
&nbsp;
          - append - keyword argument - bool - Specifies what to do if
            the file already exists (True: append to the end of it;
            False: overwrite it.)  The default is False.
&nbsp;
&nbsp;
        --- Newline handling.
&nbsp;
        write_text() converts all standard end-of-line sequences
        ('<span style="color: #000099; font-weight: bold;">\n</span>', '<span style="color: #000099; font-weight: bold;">\r</span>', and '<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>') to your platform's default end-of-line
        sequence (see os.linesep; on Windows, for example, the
        end-of-line marker is '<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>').
&nbsp;
        If you don't like your platform's default, you can override it
        using the 'linesep=' keyword argument.  If you specifically want
        write_text() to preserve the newlines as-is, use 'linesep=None'.
&nbsp;
        This applies to Unicode text the same as to 8-bit text, except
        there are three additional standard Unicode end-of-line sequences:
        u'<span style="color: #000099; font-weight: bold;">\x</span>85', u'<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\x</span>85', and u'<span style="color: #000099; font-weight: bold;">\u</span>2028'.
&nbsp;
        (This is slightly different from when you open a file for
        writing with fopen(filename, &quot;w&quot;) in C or open(filename, 'w')
        in Python.)
&nbsp;
&nbsp;
        --- Unicode
&nbsp;
        If 'text' isn't Unicode, then apart from newline handling, the
        bytes are written verbatim to the file.  The 'encoding' and
        'errors' arguments are not used and must be omitted.
&nbsp;
        If 'text' is Unicode, it is first converted to bytes using the
        specified 'encoding' (or the default encoding if 'encoding'
        isn't specified).  The 'errors' argument applies only to this
        conversion.
&nbsp;
        &quot;&quot;&quot;</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">isinstance</span><span style="color: black;">&#40;</span>text, <span style="color: #008000;">unicode</span><span style="color: black;">&#41;</span>:
            <span style="color: #ff7700;font-weight:bold;">if</span> linesep <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #008000;">None</span>:
                <span style="color: #808080; font-style: italic;"># Convert all standard end-of-line sequences to</span>
                <span style="color: #808080; font-style: italic;"># ordinary newline characters.</span>
                text = <span style="color: black;">&#40;</span>text.<span style="color: black;">replace</span><span style="color: black;">&#40;</span>u<span style="color: #483d8b;">'<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>'</span>, u<span style="color: #483d8b;">'<span style="color: #000099; font-weight: bold;">\n</span>'</span><span style="color: black;">&#41;</span>
                            .<span style="color: black;">replace</span><span style="color: black;">&#40;</span>u<span style="color: #483d8b;">'<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\x</span>85'</span>, u<span style="color: #483d8b;">'<span style="color: #000099; font-weight: bold;">\n</span>'</span><span style="color: black;">&#41;</span>
                            .<span style="color: black;">replace</span><span style="color: black;">&#40;</span>u<span style="color: #483d8b;">'<span style="color: #000099; font-weight: bold;">\r</span>'</span>, u<span style="color: #483d8b;">'<span style="color: #000099; font-weight: bold;">\n</span>'</span><span style="color: black;">&#41;</span>
                            .<span style="color: black;">replace</span><span style="color: black;">&#40;</span>u<span style="color: #483d8b;">'<span style="color: #000099; font-weight: bold;">\x</span>85'</span>, u<span style="color: #483d8b;">'<span style="color: #000099; font-weight: bold;">\n</span>'</span><span style="color: black;">&#41;</span>
                            .<span style="color: black;">replace</span><span style="color: black;">&#40;</span>u<span style="color: #483d8b;">'<span style="color: #000099; font-weight: bold;">\u</span>2028'</span>, u<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>
                text = text.<span style="color: black;">replace</span><span style="color: black;">&#40;</span>u<span style="color: #483d8b;">'<span style="color: #000099; font-weight: bold;">\n</span>'</span>, linesep<span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">if</span> encoding <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #008000;">None</span>:
                encoding = <span style="color: #dc143c;">sys</span>.<span style="color: black;">getdefaultencoding</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
            <span style="color: #dc143c;">bytes</span> = text.<span style="color: black;">encode</span><span style="color: black;">&#40;</span>encoding, errors<span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">else</span>:
            <span style="color: #808080; font-style: italic;"># It is an error to specify an encoding if 'text' is</span>
            <span style="color: #808080; font-style: italic;"># an 8-bit string.</span>
            <span style="color: #ff7700;font-weight:bold;">assert</span> encoding <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #008000;">None</span>
&nbsp;
            <span style="color: #ff7700;font-weight:bold;">if</span> linesep <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #008000;">None</span>:
                text = <span style="color: black;">&#40;</span>text.<span style="color: black;">replace</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>'</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;">replace</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'<span style="color: #000099; font-weight: bold;">\r</span>'</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: #dc143c;">bytes</span> = text.<span style="color: black;">replace</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'<span style="color: #000099; font-weight: bold;">\n</span>'</span>, linesep<span style="color: black;">&#41;</span>
&nbsp;
        <span style="color: #008000;">self</span>.<span style="color: black;">write_bytes</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">bytes</span>, append<span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> lines<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, encoding=<span style="color: #008000;">None</span>, errors=<span style="color: #483d8b;">'strict'</span>, retain=<span style="color: #008000;">True</span><span style="color: black;">&#41;</span>:
        r<span style="color: #483d8b;">&quot;&quot;&quot; Open this file, read all lines, return them in a list.
&nbsp;
        Optional arguments:
            encoding - The Unicode encoding (or character set) of
                the file.  The default is None, meaning the content
                of the file is read as 8-bit characters and returned
                as a list of (non-Unicode) str objects.
            errors - How to handle Unicode errors; see help(str.decode)
                for the options.  Default is 'strict'
            retain - If true, retain newline characters; but all newline
                character combinations ('<span style="color: #000099; font-weight: bold;">\r</span>', '<span style="color: #000099; font-weight: bold;">\n</span>', '<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>') are
                translated to '<span style="color: #000099; font-weight: bold;">\n</span>'.  If false, newline characters are
                stripped off.  Default is True.
&nbsp;
        This uses 'U' mode.
        &quot;&quot;&quot;</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> encoding <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #008000;">None</span> <span style="color: #ff7700;font-weight:bold;">and</span> retain:
            <span style="color: #ff7700;font-weight:bold;">with</span> <span style="color: #008000;">self</span>.<span style="color: #008000;">open</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'U'</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">as</span> f:
                <span style="color: #ff7700;font-weight:bold;">return</span> f.<span style="color: black;">readlines</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">else</span>:
            <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>.<span style="color: black;">text</span><span style="color: black;">&#40;</span>encoding, errors<span style="color: black;">&#41;</span>.<span style="color: black;">splitlines</span><span style="color: black;">&#40;</span>retain<span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> write_lines<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, lines, encoding=<span style="color: #008000;">None</span>, errors=<span style="color: #483d8b;">'strict'</span>,
                    linesep=<span style="color: #dc143c;">os</span>.<span style="color: black;">linesep</span>, append=<span style="color: #008000;">False</span><span style="color: black;">&#41;</span>:
        r<span style="color: #483d8b;">&quot;&quot;&quot; Write the given lines of text to this file.
&nbsp;
        By default this overwrites any existing file at this path.
&nbsp;
        This puts a platform-specific newline sequence on every line.
        See 'linesep' below.
&nbsp;
        lines - A list of strings.
&nbsp;
        encoding - A Unicode encoding to use.  This applies only if
            'lines' contains any Unicode strings.
&nbsp;
        errors - How to handle errors in Unicode encoding.  This
            also applies only to Unicode strings.
&nbsp;
        linesep - The desired line-ending.  This line-ending is
            applied to every line.  If a line already has any
            standard line ending ('<span style="color: #000099; font-weight: bold;">\r</span>', '<span style="color: #000099; font-weight: bold;">\n</span>', '<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>', u'<span style="color: #000099; font-weight: bold;">\x</span>85',
            u'<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\x</span>85', u'<span style="color: #000099; font-weight: bold;">\u</span>2028'), that will be stripped off and
            this will be used instead.  The default is os.linesep,
            which is platform-dependent ('<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>' on Windows, '<span style="color: #000099; font-weight: bold;">\n</span>' on
            Unix, etc.)  Specify None to write the lines as-is,
            like file.writelines().
&nbsp;
        Use the keyword argument append=True to append lines to the
        file.  The default is to overwrite the file.  Warning:
        When you use this with Unicode data, if the encoding of the
        existing data in the file is different from the encoding
        you specify with the encoding= parameter, the result is
        mixed-encoding data, which can really confuse someone trying
        to read the file later.
        &quot;&quot;&quot;</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> append:
            mode = <span style="color: #483d8b;">'ab'</span>
        <span style="color: #ff7700;font-weight:bold;">else</span>:
            mode = <span style="color: #483d8b;">'wb'</span>
        <span style="color: #ff7700;font-weight:bold;">with</span> <span style="color: #008000;">self</span>.<span style="color: #008000;">open</span><span style="color: black;">&#40;</span>mode<span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">as</span> f:
            <span style="color: #ff7700;font-weight:bold;">for</span> line <span style="color: #ff7700;font-weight:bold;">in</span> lines:
                isUnicode = <span style="color: #008000;">isinstance</span><span style="color: black;">&#40;</span>line, <span style="color: #008000;">unicode</span><span style="color: black;">&#41;</span>
                <span style="color: #ff7700;font-weight:bold;">if</span> linesep <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #008000;">None</span>:
                    <span style="color: #808080; font-style: italic;"># Strip off any existing line-end and add the</span>
                    <span style="color: #808080; font-style: italic;"># specified linesep string.</span>
                    <span style="color: #ff7700;font-weight:bold;">if</span> isUnicode:
                        <span style="color: #ff7700;font-weight:bold;">if</span> line<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;">in</span> <span style="color: black;">&#40;</span>u<span style="color: #483d8b;">'<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>'</span>, u<span style="color: #483d8b;">'<span style="color: #000099; font-weight: bold;">\x</span>0d<span style="color: #000099; font-weight: bold;">\x</span>85'</span><span style="color: black;">&#41;</span>:
                            line = line<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;">elif</span> line<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;">in</span> <span style="color: black;">&#40;</span>u<span style="color: #483d8b;">'<span style="color: #000099; font-weight: bold;">\r</span>'</span>, u<span style="color: #483d8b;">'<span style="color: #000099; font-weight: bold;">\n</span>'</span>,
                                           u<span style="color: #483d8b;">'<span style="color: #000099; font-weight: bold;">\x</span>85'</span>, u<span style="color: #483d8b;">'<span style="color: #000099; font-weight: bold;">\u</span>2028'</span><span style="color: black;">&#41;</span>:
                            line = line<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;">else</span>:
                        <span style="color: #ff7700;font-weight:bold;">if</span> line<span style="color: black;">&#91;</span>-<span style="color: #ff4500;">2</span>:<span style="color: black;">&#93;</span> == <span style="color: #483d8b;">'<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>'</span>:
                            line = line<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;">elif</span> line<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;">in</span> <span style="color: black;">&#40;</span><span style="color: #483d8b;">'<span style="color: #000099; font-weight: bold;">\r</span>'</span>, <span style="color: #483d8b;">'<span style="color: #000099; font-weight: bold;">\n</span>'</span><span style="color: black;">&#41;</span>:
                            line = line<span style="color: black;">&#91;</span>:-<span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span>
                    line += linesep
                <span style="color: #ff7700;font-weight:bold;">if</span> isUnicode:
                    <span style="color: #ff7700;font-weight:bold;">if</span> encoding <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #008000;">None</span>:
                        encoding = <span style="color: #dc143c;">sys</span>.<span style="color: black;">getdefaultencoding</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
                    line = line.<span style="color: black;">encode</span><span style="color: black;">&#40;</span>encoding, errors<span style="color: black;">&#41;</span>
                f.<span style="color: black;">write</span><span style="color: black;">&#40;</span>line<span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> read_md5<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">&quot;&quot;&quot; Calculate the md5 hash for this file.
&nbsp;
        This reads through the entire file.
        &quot;&quot;&quot;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>.<span style="color: black;">read_hash</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'md5'</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> _hash<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, hash_name<span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">with</span> <span style="color: #008000;">self</span>.<span style="color: #008000;">open</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'rb'</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">as</span> f:
            m = hashlib.<span style="color: #dc143c;">new</span><span style="color: black;">&#40;</span>hash_name<span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">while</span> <span style="color: #008000;">True</span>:
                d = f.<span style="color: black;">read</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">8192</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> d:
                    <span style="color: #ff7700;font-weight:bold;">break</span>
                m.<span style="color: black;">update</span><span style="color: black;">&#40;</span>d<span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">return</span> m
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> read_hash<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, hash_name<span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">&quot;&quot;&quot; Calculate given hash for this file.
&nbsp;
        List of supported hashes can be obtained from hashlib package. This
        reads the entire file.
        &quot;&quot;&quot;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>._hash<span style="color: black;">&#40;</span>hash_name<span style="color: black;">&#41;</span>.<span style="color: black;">digest</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> read_hexhash<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, hash_name<span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">&quot;&quot;&quot; Calculate given hash for this file, returning hexdigest.
&nbsp;
        List of supported hashes can be obtained from hashlib package. This
        reads the entire file.
        &quot;&quot;&quot;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>._hash<span style="color: black;">&#40;</span>hash_name<span style="color: black;">&#41;</span>.<span style="color: black;">hexdigest</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
&nbsp;
&nbsp;
    <span style="color: #808080; font-style: italic;">#&lt;sm&gt;</span>
    <span style="color: #808080; font-style: italic;"># Comme les fonctions, les méthodes peuvent être définies sur une ligne si</span>
    <span style="color: #808080; font-style: italic;"># le bloc ne fait qu'une ligne de taille. On utilise ça quand la fonction</span>
    <span style="color: #808080; font-style: italic;"># est juste un alias un peu avancé comme ici pour garder un style quasi</span>
    <span style="color: #808080; font-style: italic;"># déclaratif.</span>
    <span style="color: #808080; font-style: italic;">#&lt;/sm&gt;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># --- Methods for querying the filesystem.</span>
    <span style="color: #808080; font-style: italic;"># N.B. On some platforms, the os.path functions may be implemented in C</span>
    <span style="color: #808080; font-style: italic;"># (e.g. isdir on Windows, Python 3.2.2), and compiled functions don't get</span>
    <span style="color: #808080; font-style: italic;"># bound. Playing it safe and wrapping them all in method calls.</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> isabs<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;">module</span>.<span style="color: black;">isabs</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;">def</span> exists<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;">module</span>.<span style="color: black;">exists</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;">def</span> isdir<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;">module</span>.<span style="color: black;">isdir</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;">def</span> isfile<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;">module</span>.<span style="color: black;">isfile</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;">def</span> islink<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;">module</span>.<span style="color: black;">islink</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;">def</span> ismount<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;">module</span>.<span style="color: black;">ismount</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> samefile<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;">module</span>.<span style="color: black;">samefile</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> getatime<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;">module</span>.<span style="color: black;">getatime</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>
    atime = <span style="color: #008000;">property</span><span style="color: black;">&#40;</span>
        getatime, <span style="color: #008000;">None</span>, <span style="color: #008000;">None</span>,
        <span style="color: #483d8b;">&quot;&quot;&quot; Last access time of the file. &quot;&quot;&quot;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> getmtime<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;">module</span>.<span style="color: black;">getmtime</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>
    mtime = <span style="color: #008000;">property</span><span style="color: black;">&#40;</span>
        getmtime, <span style="color: #008000;">None</span>, <span style="color: #008000;">None</span>,
        <span style="color: #483d8b;">&quot;&quot;&quot; Last-modified time of the file. &quot;&quot;&quot;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> getctime<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;">module</span>.<span style="color: black;">getctime</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>
    ctime = <span style="color: #008000;">property</span><span style="color: black;">&#40;</span>
        getctime, <span style="color: #008000;">None</span>, <span style="color: #008000;">None</span>,
        <span style="color: #483d8b;">&quot;&quot;&quot; Creation time of the file. &quot;&quot;&quot;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> getsize<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;">module</span>.<span style="color: black;">getsize</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>
    size = <span style="color: #008000;">property</span><span style="color: black;">&#40;</span>
        getsize, <span style="color: #008000;">None</span>, <span style="color: #008000;">None</span>,
        <span style="color: #483d8b;">&quot;&quot;&quot; Size of the file, in bytes. &quot;&quot;&quot;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;">#&lt;sm&gt;</span>
    <span style="color: #808080; font-style: italic;"># Technique intéressante : on peut générer dynamiquement le corps de</span>
    <span style="color: #808080; font-style: italic;"># la classe. En effet, il peut contenir des if, des try, des for, etc.</span>
    <span style="color: #808080; font-style: italic;"># Ici par exemple, on ne définit la méthode access() que si le module</span>
    <span style="color: #808080; font-style: italic;"># 'os' possède l'attribut 'access'.</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Si ce n'est pas la cas, la classe n'aura pas cette méthode.</span>
    <span style="color: #808080; font-style: italic;">#&lt;/sm&gt;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">hasattr</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">os</span>, <span style="color: #483d8b;">'access'</span><span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">def</span> access<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, mode<span style="color: black;">&#41;</span>:
            <span style="color: #483d8b;">&quot;&quot;&quot; Return true if current user has access to this path.
&nbsp;
            mode - One of the constants os.F_OK, os.R_OK, os.W_OK, os.X_OK
            &quot;&quot;&quot;</span>
            <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #dc143c;">os</span>.<span style="color: black;">access</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, mode<span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #dc143c;">stat</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">&quot;&quot;&quot; Perform a stat() system call on this path. &quot;&quot;&quot;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #dc143c;">os</span>.<span style="color: #dc143c;">stat</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> lstat<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">&quot;&quot;&quot; Like path.stat(), but do not follow symbolic links. &quot;&quot;&quot;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #dc143c;">os</span>.<span style="color: black;">lstat</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>
&nbsp;
&nbsp;
    <span style="color: #808080; font-style: italic;">#&lt;sm&gt;</span>
    <span style="color: #808080; font-style: italic;"># Une autre technique intéressante : une des rares utilisation du double</span>
    <span style="color: #808080; font-style: italic;"># '_' en tant que préfixe qui ait du sens. '__method' interdit d'accéder</span>
    <span style="color: #808080; font-style: italic;"># directement à la méthode depuis l'extérieur. C'est ce qu'on a de plus</span>
    <span style="color: #808080; font-style: italic;"># proche de &quot;private&quot; en Python.</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Ce n'est pas sécurisé du tout (on peut le contourner) et cela empêche le</span>
    <span style="color: #808080; font-style: italic;"># monkey patching et autres mesures de contournement en cas de besoin,</span>
    <span style="color: #808080; font-style: italic;"># donc je ne vous  recommande pas de le faire.</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Mais dans ce cas, ces méthodes sont volontairement définies ainsi pour</span>
    <span style="color: #808080; font-style: italic;"># être invisibles puis un peu plus pas, si win32security ou pwd existent</span>
    <span style="color: #808080; font-style: italic;"># (rappelez-vous, ce sont des dépendances optionnelles), alors elles sont</span>
    <span style="color: #808080; font-style: italic;"># aliasées pour être rendues disponibles.</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Il y a 3 implémentations (3 méthodes: un pour windows, une pour unix et</span>
    <span style="color: #808080; font-style: italic;"># une pour le cas où aucun module n'est présent) pour la même</span>
    <span style="color: #808080; font-style: italic;"># fonctionnalitéé, et l'une des 3 méthodes est utilisée comme</span>
    <span style="color: #808080; font-style: italic;"># implémentation de get_owner().</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># On aurait pu tout mettre dans des if directement, mais ça ferait des</span>
    <span style="color: #808080; font-style: italic;"># gros blocs moins lisibles. Ici il est facile de comprendre le code</span>
    <span style="color: #808080; font-style: italic;"># source.</span>
    <span style="color: #808080; font-style: italic;">#&lt;/sm&gt;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> __get_owner_windows<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        r<span style="color: #483d8b;">&quot;&quot;&quot;
        Return the name of the owner of this file or directory. Follow
        symbolic links.
&nbsp;
        Return a name of the form ur'DOMAIN<span style="color: #000099; font-weight: bold;">\U</span>ser Name'; may be a group.
        &quot;&quot;&quot;</span>
        desc = win32security.<span style="color: black;">GetFileSecurity</span><span style="color: black;">&#40;</span>
            <span style="color: #008000;">self</span>, win32security.<span style="color: black;">OWNER_SECURITY_INFORMATION</span><span style="color: black;">&#41;</span>
        sid = desc.<span style="color: black;">GetSecurityDescriptorOwner</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        account, domain, typecode = win32security.<span style="color: black;">LookupAccountSid</span><span style="color: black;">&#40;</span><span style="color: #008000;">None</span>, sid<span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> domain + u<span style="color: #483d8b;">'<span style="color: #000099; font-weight: bold;">\\</span>'</span> + account
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> __get_owner_unix<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">&quot;&quot;&quot;
        Return the name of the owner of this file or directory. Follow
        symbolic links.
        &quot;&quot;&quot;</span>
        st = <span style="color: #008000;">self</span>.<span style="color: #dc143c;">stat</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #dc143c;">pwd</span>.<span style="color: black;">getpwuid</span><span style="color: black;">&#40;</span>st.<span style="color: black;">st_uid</span><span style="color: black;">&#41;</span>.<span style="color: black;">pw_name</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> __get_owner_not_implemented<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;">raise</span> <span style="color: #008000;">NotImplementedError</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Ownership not available on this platform.&quot;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #483d8b;">'win32security'</span> <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">globals</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
        get_owner = __get_owner_windows
    <span style="color: #ff7700;font-weight:bold;">elif</span> <span style="color: #483d8b;">'pwd'</span> <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">globals</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
        get_owner = __get_owner_unix
    <span style="color: #ff7700;font-weight:bold;">else</span>:
        get_owner = __get_owner_not_implemented
&nbsp;
    owner = <span style="color: #008000;">property</span><span style="color: black;">&#40;</span>
        get_owner, <span style="color: #008000;">None</span>, <span style="color: #008000;">None</span>,
        <span style="color: #483d8b;">&quot;&quot;&quot; Name of the owner of this file or directory. &quot;&quot;&quot;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">hasattr</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">os</span>, <span style="color: #483d8b;">'statvfs'</span><span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #dc143c;">statvfs</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
            <span style="color: #483d8b;">&quot;&quot;&quot; Perform a statvfs() system call on this path. &quot;&quot;&quot;</span>
            <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #dc143c;">os</span>.<span style="color: #dc143c;">statvfs</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">hasattr</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">os</span>, <span style="color: #483d8b;">'pathconf'</span><span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">def</span> pathconf<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, name<span style="color: black;">&#41;</span>:
            <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #dc143c;">os</span>.<span style="color: black;">pathconf</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, name<span style="color: black;">&#41;</span>
&nbsp;
&nbsp;
    <span style="color: #808080; font-style: italic;">#&lt;sm&gt;</span>
    <span style="color: #808080; font-style: italic;"># Pas d'autres commentaires après celui-là. jusqu'à la classe de fin.</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Les méthodes suivantes retournent 'self' bien que ce ne soit</span>
    <span style="color: #808080; font-style: italic;"># pas nécessaire.</span>
    <span style="color: #808080; font-style: italic;"># Par exemple path('/tmp/test').chmod(777) va retourner path('/tmp/test')</span>
    <span style="color: #808080; font-style: italic;"># alors que tout ce qu'on lui demande, c'est de changer la permission</span>
    <span style="color: #808080; font-style: italic;"># du dossier. On le fait pour permettre le chaîning, c'est à dire</span>
    <span style="color: #808080; font-style: italic;"># d'autoriser les appels enchainés comme :</span>
    <span style="color: #808080; font-style: italic;"># path('/tmp/test').chmod(777).rename('/tmp/essai').mkdir('ping')</span>
    <span style="color: #808080; font-style: italic;">#&lt;/sm&gt;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;">#</span>
    <span style="color: #808080; font-style: italic;"># --- Modifying operations on files and directories</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> utime<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, times<span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">&quot;&quot;&quot; Set the access and modified times of this file. &quot;&quot;&quot;</span>
        <span style="color: #dc143c;">os</span>.<span style="color: black;">utime</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, times<span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> chmod<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, mode<span style="color: black;">&#41;</span>:
        <span style="color: #dc143c;">os</span>.<span style="color: black;">chmod</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, mode<span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">hasattr</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">os</span>, <span style="color: #483d8b;">'chown'</span><span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">def</span> chown<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, uid, gid<span style="color: black;">&#41;</span>:
            <span style="color: #dc143c;">os</span>.<span style="color: black;">chown</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, uid, gid<span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> rename<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, <span style="color: #dc143c;">new</span><span style="color: black;">&#41;</span>:
        <span style="color: #dc143c;">os</span>.<span style="color: black;">rename</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, <span style="color: #dc143c;">new</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>._next_class<span style="color: black;">&#40;</span><span style="color: #dc143c;">new</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> renames<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, <span style="color: #dc143c;">new</span><span style="color: black;">&#41;</span>:
        <span style="color: #dc143c;">os</span>.<span style="color: black;">renames</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, <span style="color: #dc143c;">new</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>._next_class<span style="color: black;">&#40;</span><span style="color: #dc143c;">new</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;">#</span>
    <span style="color: #808080; font-style: italic;"># --- Create/delete operations on directories</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> mkdir<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, mode=0777<span style="color: black;">&#41;</span>:
        <span style="color: #dc143c;">os</span>.<span style="color: black;">mkdir</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, mode<span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> mkdir_p<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, mode=0777<span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">try</span>:
            <span style="color: #008000;">self</span>.<span style="color: black;">mkdir</span><span style="color: black;">&#40;</span>mode<span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">OSError</span>, e:
            <span style="color: #ff7700;font-weight:bold;">if</span> e.<span style="color: #dc143c;">errno</span> <span style="color: #66cc66;">!</span>= <span style="color: #dc143c;">errno</span>.<span style="color: black;">EEXIST</span>:
                <span style="color: #ff7700;font-weight:bold;">raise</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> makedirs<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, mode=0777<span style="color: black;">&#41;</span>:
        <span style="color: #dc143c;">os</span>.<span style="color: black;">makedirs</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, mode<span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> makedirs_p<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, mode=0777<span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">try</span>:
            <span style="color: #008000;">self</span>.<span style="color: black;">makedirs</span><span style="color: black;">&#40;</span>mode<span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">OSError</span>, e:
            <span style="color: #ff7700;font-weight:bold;">if</span> e.<span style="color: #dc143c;">errno</span> <span style="color: #66cc66;">!</span>= <span style="color: #dc143c;">errno</span>.<span style="color: black;">EEXIST</span>:
                <span style="color: #ff7700;font-weight:bold;">raise</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> rmdir<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #dc143c;">os</span>.<span style="color: black;">rmdir</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> rmdir_p<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;">try</span>:
            <span style="color: #008000;">self</span>.<span style="color: black;">rmdir</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">OSError</span>, e:
            <span style="color: #ff7700;font-weight:bold;">if</span> e.<span style="color: #dc143c;">errno</span> <span style="color: #66cc66;">!</span>= <span style="color: #dc143c;">errno</span>.<span style="color: black;">ENOTEMPTY</span> <span style="color: #ff7700;font-weight:bold;">and</span> e.<span style="color: #dc143c;">errno</span> <span style="color: #66cc66;">!</span>= <span style="color: #dc143c;">errno</span>.<span style="color: black;">EEXIST</span>:
                <span style="color: #ff7700;font-weight:bold;">raise</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> removedirs<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #dc143c;">os</span>.<span style="color: black;">removedirs</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> removedirs_p<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;">try</span>:
            <span style="color: #008000;">self</span>.<span style="color: black;">removedirs</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">OSError</span>, e:
            <span style="color: #ff7700;font-weight:bold;">if</span> e.<span style="color: #dc143c;">errno</span> <span style="color: #66cc66;">!</span>= <span style="color: #dc143c;">errno</span>.<span style="color: black;">ENOTEMPTY</span> <span style="color: #ff7700;font-weight:bold;">and</span> e.<span style="color: #dc143c;">errno</span> <span style="color: #66cc66;">!</span>= <span style="color: #dc143c;">errno</span>.<span style="color: black;">EEXIST</span>:
                <span style="color: #ff7700;font-weight:bold;">raise</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># --- Modifying operations on files</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> touch<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">&quot;&quot;&quot; Set the access/modified times of this file to the current time.
        Create the file if it does not exist.
        &quot;&quot;&quot;</span>
        fd = <span style="color: #dc143c;">os</span>.<span style="color: #008000;">open</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, <span style="color: #dc143c;">os</span>.<span style="color: black;">O_WRONLY</span> | <span style="color: #dc143c;">os</span>.<span style="color: black;">O_CREAT</span>, 0666<span style="color: black;">&#41;</span>
        <span style="color: #dc143c;">os</span>.<span style="color: black;">close</span><span style="color: black;">&#40;</span>fd<span style="color: black;">&#41;</span>
        <span style="color: #dc143c;">os</span>.<span style="color: black;">utime</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, <span style="color: #008000;">None</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> remove<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #dc143c;">os</span>.<span style="color: black;">remove</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> remove_p<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;">try</span>:
            <span style="color: #008000;">self</span>.<span style="color: black;">unlink</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">OSError</span>, e:
            <span style="color: #ff7700;font-weight:bold;">if</span> e.<span style="color: #dc143c;">errno</span> <span style="color: #66cc66;">!</span>= <span style="color: #dc143c;">errno</span>.<span style="color: black;">ENOENT</span>:
                <span style="color: #ff7700;font-weight:bold;">raise</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> unlink<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #dc143c;">os</span>.<span style="color: black;">unlink</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> unlink_p<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;">remove_p</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># --- Links</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">hasattr</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">os</span>, <span style="color: #483d8b;">'link'</span><span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">def</span> link<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, newpath<span style="color: black;">&#41;</span>:
            <span style="color: #483d8b;">&quot;&quot;&quot; Create a hard link at 'newpath', pointing to this file. &quot;&quot;&quot;</span>
            <span style="color: #dc143c;">os</span>.<span style="color: black;">link</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, newpath<span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>._next_class<span style="color: black;">&#40;</span>newpath<span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">hasattr</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">os</span>, <span style="color: #483d8b;">'symlink'</span><span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">def</span> symlink<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, newlink<span style="color: black;">&#41;</span>:
            <span style="color: #483d8b;">&quot;&quot;&quot; Create a symbolic link at 'newlink', pointing here. &quot;&quot;&quot;</span>
            <span style="color: #dc143c;">os</span>.<span style="color: black;">symlink</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, newlink<span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>._next_class<span style="color: black;">&#40;</span>newlink<span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">hasattr</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">os</span>, <span style="color: #483d8b;">'readlink'</span><span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">def</span> readlink<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
            <span style="color: #483d8b;">&quot;&quot;&quot; Return the path to which this symbolic link points.
&nbsp;
            The result may be an absolute or a relative path.
            &quot;&quot;&quot;</span>
            <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>._next_class<span style="color: black;">&#40;</span><span style="color: #dc143c;">os</span>.<span style="color: black;">readlink</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
        <span style="color: #ff7700;font-weight:bold;">def</span> readlinkabs<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
            <span style="color: #483d8b;">&quot;&quot;&quot; Return the path to which this symbolic link points.
&nbsp;
            The result is always an absolute path.
            &quot;&quot;&quot;</span>
            p = <span style="color: #008000;">self</span>.<span style="color: black;">readlink</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">if</span> p.<span style="color: black;">isabs</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
                <span style="color: #ff7700;font-weight:bold;">return</span> p
            <span style="color: #ff7700;font-weight:bold;">else</span>:
                <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">parent</span> / p<span style="color: black;">&#41;</span>.<span style="color: black;">abspath</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;">#</span>
    <span style="color: #808080; font-style: italic;"># --- High-level functions from shutil</span>
&nbsp;
    copyfile = <span style="color: #dc143c;">shutil</span>.<span style="color: black;">copyfile</span>
    copymode = <span style="color: #dc143c;">shutil</span>.<span style="color: black;">copymode</span>
    copystat = <span style="color: #dc143c;">shutil</span>.<span style="color: black;">copystat</span>
    <span style="color: #dc143c;">copy</span> = <span style="color: #dc143c;">shutil</span>.<span style="color: #dc143c;">copy</span>
    copy2 = <span style="color: #dc143c;">shutil</span>.<span style="color: black;">copy2</span>
    copytree = <span style="color: #dc143c;">shutil</span>.<span style="color: black;">copytree</span>
    <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">hasattr</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">shutil</span>, <span style="color: #483d8b;">'move'</span><span style="color: black;">&#41;</span>:
        move = <span style="color: #dc143c;">shutil</span>.<span style="color: black;">move</span>
    rmtree = <span style="color: #dc143c;">shutil</span>.<span style="color: black;">rmtree</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> rmtree_p<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;">try</span>:
            <span style="color: #008000;">self</span>.<span style="color: black;">rmtree</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">OSError</span>, e:
            <span style="color: #ff7700;font-weight:bold;">if</span> e.<span style="color: #dc143c;">errno</span> <span style="color: #66cc66;">!</span>= <span style="color: #dc143c;">errno</span>.<span style="color: black;">ENOENT</span>:
                <span style="color: #ff7700;font-weight:bold;">raise</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>
&nbsp;
    <span style="color: #808080; font-style: italic;">#</span>
    <span style="color: #808080; font-style: italic;"># --- Special stuff from os</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">hasattr</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">os</span>, <span style="color: #483d8b;">'chroot'</span><span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">def</span> chroot<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
            <span style="color: #dc143c;">os</span>.<span style="color: black;">chroot</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">hasattr</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">os</span>, <span style="color: #483d8b;">'startfile'</span><span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">def</span> startfile<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
            <span style="color: #dc143c;">os</span>.<span style="color: black;">startfile</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>
&nbsp;
&nbsp;
<span style="color: #808080; font-style: italic;">#&lt;sm&gt;</span>
<span style="color: #808080; font-style: italic;"># La seule spécificité de cette classe est d'overrider la méthode __new__ qui</span>
<span style="color: #808080; font-style: italic;"># est le véritable constructeur en Python (__init__ n'est pas un constructeur)</span>
<span style="color: #808080; font-style: italic;"># L'auteur le fait car tempdir hérite de path qui hérite d'unicode. Or, tous</span>
<span style="color: #808080; font-style: italic;"># les types non-mutables (int, tuple, str, etc, et donc unicode), n'étant pas</span>
<span style="color: #808080; font-style: italic;"># modifiables, ne peuvent être changés dans __init__. Ici __new__ est</span>
<span style="color: #808080; font-style: italic;"># utilisé pour retourner un path tout en créant un dossier temporaire, ce</span>
<span style="color: #808080; font-style: italic;"># qui ne marcherait pas dans __init__. Il est très rare d'avoir besoin de</span>
<span style="color: #808080; font-style: italic;"># s'occuper de __new__.</span>
<span style="color: #808080; font-style: italic;">#&lt;/sm&gt;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> tempdir<span style="color: black;">&#40;</span>path<span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot;
    A temporary directory via tempfile.mkdtemp, and constructed with the
    same parameters that you can use as a context manager.
&nbsp;
    Example:
&nbsp;
        with tempdir() as d:
            # do stuff with the path object &quot;d&quot;
&nbsp;
        # here the directory is deleted automatically
    &quot;&quot;&quot;</span>
&nbsp;
    @ClassProperty
    @<span style="color: #008000;">classmethod</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> _next_class<span style="color: black;">&#40;</span>cls<span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> path
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__new__</span><span style="color: black;">&#40;</span>cls, <span style="color: #66cc66;">*</span>args, <span style="color: #66cc66;">**</span>kwargs<span style="color: black;">&#41;</span>:
        dirname = <span style="color: #dc143c;">tempfile</span>.<span style="color: black;">mkdtemp</span><span style="color: black;">&#40;</span><span style="color: #66cc66;">*</span>args, <span style="color: #66cc66;">**</span>kwargs<span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">super</span><span style="color: black;">&#40;</span>tempdir, cls<span style="color: black;">&#41;</span>.<span style="color: #0000cd;">__new__</span><span style="color: black;">&#40;</span>cls, dirname<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: #66cc66;">*</span>args, <span style="color: #66cc66;">**</span>kwargs<span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">pass</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> __enter__<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>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> __exit__<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, exc_type, exc_value, <span style="color: #dc143c;">traceback</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> exc_value:
            <span style="color: #008000;">self</span>.<span style="color: black;">rmtree</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>C&#8217;est une bibliothèque très complète et propre, et bien qu&#8217;il y est quelques astuces ici et là, vous avez pu constaté que l&#8217;usage de la POO reste tout à fait accessible : héritage simple, déclaration de méthode, properties, etc. On ne fait pas beaucoup de folies.</p>
<p>Il n&#8217;y a pas besoin de faire les choses compliquées avec la POO, on peut faire des choses tout à fait ordinaires et utiles.</p>
<p>Pour le dernier tuto de la série, on tapera dans la magie noire, à savoir les métaclasses. Tintintin.</p>
<p>P.S: cet article a été sponsorisé par le plugin Sublime Text <a href="https://github.com/ehuss/Sublime-Wrap-Plus">Wraps Plus</a>. Avec Wraps Plus, plus de caractères en sus !</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=5912&amp;md5=5ee04086e4fda5af17ffc872144fb631" 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>


