<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Sam &#38; Max: Python, Django, Git et du cul</title>
	<atom:link href="http://sametmax.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://sametmax.com</link>
	<description>Deux développeurs en vadrouille qui se sortent les doigts du code</description>
	<lastBuildDate>Fri, 24 May 2013 10:27:41 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
	<atom:link rel="payment" title="Flattr this!" href="https://flattr.com/submit/auto?user_id=sam_et_max&amp;popout=1&amp;url=http%3A%2F%2Fsametmax.com%2F&amp;language=en_US&amp;category=text&amp;title=Sam+%26amp%3B+Max%3A+Python%2C+Django%2C+Git+et+du+cul&amp;description=Deux+d%C3%A9veloppeurs+en+vadrouille+qui+se+sortent+les+doigts+du+code&amp;tags=blog" type="text/html" />
		<item>
		<title>Forcer une identity SSH pour un host en particulier</title>
		<link>http://sametmax.com/forcer-une-identity-ssh-pour-un-host-en-particulier/</link>
		<comments>http://sametmax.com/forcer-une-identity-ssh-pour-un-host-en-particulier/#comments</comments>
		<pubDate>Fri, 24 May 2013 10:25:45 +0000</pubDate>
		<dc:creator>Sam</dc:creator>
				<category><![CDATA[Administration System]]></category>
		<category><![CDATA[git]]></category>
		<category><![CDATA[host]]></category>
		<category><![CDATA[ssh]]></category>

		<guid isPermaLink="false">http://sametmax.com/?p=6211</guid>
		<description><![CDATA[Vous avez accumulé un certain nombre de clés SSH, et pour certains serveur ou certains sites Web (github, bitbucket...), vous voulez utiliser une clé SSH et pas une autre. ]]></description>
			<content:encoded><![CDATA[<p>Vous avez accumulé un certain nombre de clés SSH, et pour certains serveur ou certains sites Web (github, bitbucket&#8230;), vous voulez utiliser une clé SSH et pas une autre. Ce serait en effet dommage de pusher votre commit Git avec la mauvaise identité.</p>
<p>Sous unix, le fichier <em>~/.ssh/config</em> est votre ami, rajoutez lui :</p>
<pre>Host Un alias pour l'host
HostName Une IP ou un nom de domaine pour l'host
User votre nom d'utilisateur
IdentityFile le fichier de clé public à utiliser
</pre>
<p>Par exemple :</p>
<pre>Host bitbucket.org
HostName bitbucket.org
User sam
IdentityFile ~/.ssh/sam.pub

Host local-dev
HostName 192.169.0.10
User dev
IdentityFile ~/.ssh/local-dev.pub</pre>
<p>On peut créer plusieurs Host pour le même hostname, avec des résultats intéressant quand on a <a href="http://sametmax.com/utiliser-deux-comptes-github-separement/">plusieurs identités en ligne</a>.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=6211&amp;md5=341e7230ee7dfd3e7d2fa1a0844588eb" title="Flattr" target="_blank"><img src="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://sametmax.com/forcer-une-identity-ssh-pour-un-host-en-particulier/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		<atom:link rel="payment" title="Flattr this!" href="https://flattr.com/submit/auto?user_id=sam_et_max&amp;popout=1&amp;url=http%3A%2F%2Fsametmax.com%2Fforcer-une-identity-ssh-pour-un-host-en-particulier%2F&amp;language=en_GB&amp;category=text&amp;title=Forcer+une+identity+SSH+pour+un+host+en+particulier&amp;description=Vous+avez+accumul%C3%A9+un+certain+nombre+de+cl%C3%A9s+SSH%2C+et+pour+certains+serveur+ou+certains+sites+Web+%28github%2C+bitbucket%26%238230%3B%29%2C+vous+voulez+utiliser+une+cl%C3%A9+SSH+et+pas+une+autre.+Ce...&amp;tags=git%2Chost%2Cssh%2Cblog" type="text/html" />
<enclosure url="http://sametmax.com/wp-content/uploads/2013/05/tX7W5vZ.jpg" length="197388" type="image/jpg" />	</item>
		<item>
		<title>Avez vous une méthode &#8220;propre&#8221; pour jouer avec des Objets du model sans les sauvegarder en BDD sur #Django ?</title>
		<link>http://sametmax.com/avez-vous-un-methode-propre-pour-jouer-avec-des-objets-du-model-sans-les-sauvegarder-en-bdd-sur-django/</link>
		<comments>http://sametmax.com/avez-vous-un-methode-propre-pour-jouer-avec-des-objets-du-model-sans-les-sauvegarder-en-bdd-sur-django/#comments</comments>
		<pubDate>Thu, 23 May 2013 07:53:14 +0000</pubDate>
		<dc:creator>Sam</dc:creator>
				<category><![CDATA[Programmation]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[orm]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://sametmax.com/?p=6204</guid>
		<description><![CDATA[Oui]]></description>
			<content:encoded><![CDATA[<p>Mais oui <a href="https://twitter.com/CedricTouit/status/337288682803449856">cher interlocuter du Web</a>.</p>
<p>Créer un fichier &#8220;settings_test.py&#8221; à côté du fichier de settings, qui contient ç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> settings <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #66cc66;">*</span>
&nbsp;
DATABASES<span style="color: black;">&#91;</span><span style="color: #483d8b;">'default'</span><span style="color: black;">&#93;</span> = <span style="color: black;">&#123;</span>
    <span style="color: #483d8b;">'ENGINE'</span>: <span style="color: #483d8b;">'django.db.backends.sqlite3'</span>,
    <span style="color: #483d8b;">'NAME'</span>: <span style="color: #483d8b;">':memory:'</span>,
<span style="color: black;">&#125;</span></pre></div></div>

<p>Et lancer les commandes <code>./manage.py</code> avec <code>--settings=settings_test</code> :</p>
<p>Par exemple :</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">.<span style="color: #000000; font-weight: bold;">/</span>manage.py shell <span style="color: #660033;">--settings</span>=settings_test
&nbsp;
.<span style="color: #000000; font-weight: bold;">/</span>manage.py runserver <span style="color: #660033;">--settings</span>=settings_test</pre></div></div>

<p>Et voilà, toute manipulation va automatiquement sauvegarder les données en mémoire vive, et pas dans votre base de données initiale. Elles seront perdues à chaque redémarrage.</p>
<p>D&#8217;une manière générale, souvenez vous que vous pouvez faire autant de configurations alternatives et même dynamiques que vous le souhaitez avec les fichiers de settings : c&#8217;est juste du Python.</p>
<p>Si vous avez besoin des données de votre base de données initiale, vous pouvez faire une copie de la base de données et changer <code>DATABASES</code> pour pointer sur cette copie. Du coup vous manipulerez votre copie, et pas la base de données initiale.</p>
<p>Enfin, on peut <a href="https://docs.djangoproject.com/en/dev/topics/db/multi-db/">manipuler plusieurs bases de données en même temps</a> en faisant plusieurs entrées dans <code>DATABASES</code> (une &#8216;default&#8217;, une &#8216;test&#8217;, une &#8216;prod&#8217;, etc), par exemple :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">DATABASES = <span style="color: black;">&#123;</span>
    <span style="color: #483d8b;">'default'</span>: <span style="color: black;">&#123;</span>
        <span style="color: #483d8b;">'ENGINE'</span>: <span style="color: #483d8b;">'django.db.backends.postgresql_psycopg2'</span>,
        <span style="color: #483d8b;">'USER'</span>: <span style="color: #483d8b;">'postgres'</span>,
        <span style="color: #483d8b;">'PASSWORD'</span>: <span style="color: #483d8b;">'secret of mana'</span>
    <span style="color: black;">&#125;</span>
    <span style="color: #483d8b;">'test'</span>: <span style="color: black;">&#123;</span>
    <span style="color: #483d8b;">'ENGINE'</span>: <span style="color: #483d8b;">'django.db.backends.sqlite3'</span>,
    <span style="color: #483d8b;">'NAME'</span>: <span style="color: #483d8b;">':memory:'</span>,
    <span style="color: black;">&#125;</span>
<span style="color: black;">&#125;</span></pre></div></div>

<p>On peut alors spécifier la base de données à utiliser, soit par paramètre de <code>./manage.py</code> (<code>--database=bdd_a_utiliser</code>), soit directement dans le code de manipulation de l&#8217;ORM avec <code>using</code> :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> Model.<span style="color: black;">objects</span>.<span style="color: #008000;">all</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># tape dans le BDD par défaut</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> Model.<span style="color: black;">objects</span>.<span style="color: black;">using</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'test'</span><span style="color: black;">&#41;</span>.<span style="color: #008000;">all</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># tape dans la bdd de test</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> mon_model.<span style="color: black;">save</span><span style="color: black;">&#40;</span>using=<span style="color: #483d8b;">'test'</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># sauvegarde dans la bdd de test</span></pre></div></div>

 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=6204&amp;md5=228a632ae0f4e25fd348d43cb9d8ce66" title="Flattr" target="_blank"><img src="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://sametmax.com/avez-vous-un-methode-propre-pour-jouer-avec-des-objets-du-model-sans-les-sauvegarder-en-bdd-sur-django/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		<atom:link rel="payment" title="Flattr this!" href="https://flattr.com/submit/auto?user_id=sam_et_max&amp;popout=1&amp;url=http%3A%2F%2Fsametmax.com%2Favez-vous-un-methode-propre-pour-jouer-avec-des-objets-du-model-sans-les-sauvegarder-en-bdd-sur-django%2F&amp;language=en_GB&amp;category=text&amp;title=Avez+vous+une+m%C3%A9thode+%26%238220%3Bpropre%26%238221%3B+pour+jouer+avec+des+Objets+du+model+sans+les+sauvegarder+en+BDD+sur+%23Django+%3F&amp;description=Mais+oui+cher+interlocuter+du+Web.+Cr%C3%A9er+un+fichier+%26%238220%3Bsettings_test.py%26%238221%3B+%C3%A0+c%C3%B4t%C3%A9+du+fichier+de+settings%2C+qui+contient+%C3%A7a%3A+from+settings+import+%2A+%26nbsp%3B+DATABASES%26%2391%3B%27default%27%26%2393%3B+%3D+%26%23123%3B+%27ENGINE%27%3A+%27django.db.backends.sqlite3%27%2C+%27NAME%27%3A...&amp;tags=django%2Corm%2Cpython%2Cblog" type="text/html" />
<enclosure url="http://sametmax.com/wp-content/uploads/2013/05/tumblr_mmy1izVV8O1r539hzo1_500.jpg" length="51663" type="image/jpg" />	</item>
		<item>
		<title>Ça ferait de très bons noms de serveur&#8230;</title>
		<link>http://sametmax.com/ca-ferait-de-tres-bon-nom-de-serveur/</link>
		<comments>http://sametmax.com/ca-ferait-de-tres-bon-nom-de-serveur/#comments</comments>
		<pubDate>Wed, 22 May 2013 16:46:04 +0000</pubDate>
		<dc:creator>Sam</dc:creator>
				<category><![CDATA[Administration System]]></category>
		<category><![CDATA[Philo et culture]]></category>
		<category><![CDATA[meta]]></category>
		<category><![CDATA[server]]></category>

		<guid isPermaLink="false">http://sametmax.com/?p=6197</guid>
		<description><![CDATA[Non ?]]></description>
			<content:encoded><![CDATA[<ul>
<li>Hakuna matata</li>
<li>Yabadabadoo</li>
<li>Cowabunga</li>
<li>Scoobidoobidoo</li>
<li>Hey, Listen !</li>
<li>Fatality</li>
<li>GogoGadgeto</li>
<li>Doh</li>
<li>What&#8217;s up, doc</li>
<li>Beep-beep</li>
<li>Arriba</li>
<li>M&#8217;enfin</li>
<li>Par toutatis</li>
<li>Pas glop</li>
<li>Kamehameha</li>
<li>Fulguro point</li>
<li>Supercalifragilisticexpialidocious (ok, chiant à taper celui là)</li>
<li>Treguna, Mekoides, Trecorum, Satis, Dee (5 machines)</li>
</ul>
<p>Non ?</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=6197&amp;md5=3b636cd7749c8216f6112faad037e330" title="Flattr" target="_blank"><img src="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://sametmax.com/ca-ferait-de-tres-bon-nom-de-serveur/feed/</wfw:commentRss>
		<slash:comments>22</slash:comments>
		<atom:link rel="payment" title="Flattr this!" href="https://flattr.com/submit/auto?user_id=sam_et_max&amp;popout=1&amp;url=http%3A%2F%2Fsametmax.com%2Fca-ferait-de-tres-bon-nom-de-serveur%2F&amp;language=en_GB&amp;category=text&amp;title=%C3%87a+ferait+de+tr%C3%A8s+bons+noms+de+serveur%26%238230%3B&amp;description=Hakuna+matata+Yabadabadoo+Cowabunga+Scoobidoobidoo+Hey%2C+Listen+%21+Fatality+GogoGadgeto+Doh+What%26%238217%3Bs+up%2C+doc+Beep-beep+Arriba+M%26%238217%3Benfin+Par+toutatis+Pas+glop+Kamehameha+Fulguro+point+Supercalifragilisticexpialidocious+%28ok%2C+chiant+%C3%A0+taper+celui...&amp;tags=meta%2Cserver%2Cblog" type="text/html" />
<enclosure url="http://sametmax.com/wp-content/uploads/2013/05/oH2v3.jpg" length="249233" type="image/jpg" />	</item>
		<item>
		<title>Des années plus tard, je n&#8217;aime toujours pas les CBV</title>
		<link>http://sametmax.com/des-annees-plus-tards-je-naime-toujours-pas-les-cbv/</link>
		<comments>http://sametmax.com/des-annees-plus-tards-je-naime-toujours-pas-les-cbv/#comments</comments>
		<pubDate>Tue, 21 May 2013 08:52:09 +0000</pubDate>
		<dc:creator>Sam</dc:creator>
				<category><![CDATA[Programmation]]></category>
		<category><![CDATA[cbv]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://sametmax.com/?p=5976</guid>
		<description><![CDATA[Les Class Bbased Views se trouvent maintenant partout en Django. Je les comprends maintenant très bien, et les utilise souvent au mieux. Dernièrement j'ai du utiliser <a href="http://django-rest-framework.org/">django-rest-framework</a>, une très belle application, qui fait un usage utile et massif des CBV, et effectivement, cette architecture m'a rendu très productif.

Mais je maintiens ce que je dis depuis le début : ce n'est pas un pas en avant.]]></description>
			<content:encoded><![CDATA[<p>Les Class Based Views se trouvent maintenant partout en Django. Je les comprends aujourd&#8217;hui très bien, et les utilise souvent au mieux. Dernièrement j&#8217;ai dû utiliser <a href="http://django-rest-framework.org/">django-rest-framework</a>, une très belle application, qui fait un usage utile et massif des CBV, et effectivement, cette architecture m&#8217;a rendu très productif.</p>
<p>Mais je maintiens ce que je dis depuis le début : ce n&#8217;est pas un pas en avant.</p>
<p>D&#8217;abord, qui dit CBV dit référence constante à la documentation. J&#8217;ai été productif avec CBV parce que :</p>
<ul>
<li>Je connais l&#8217;API Django sur le bout des doigts.</li>
<li>Je comprends parfaitement les CBV (et la POO en Python en général).</li>
<li>Je lis très vite, et j&#8217;ai l&#8217;habitude de fouiller dans les docs.</li>
<li>Je me balade dans le code source naturellement.</li>
</ul>
<p>Mais ce n&#8217;est pas comme ça que c&#8217;est censé être. Si vous utilisez une belle API, comme <a href="http://sametmax.com/sept-petites-libs-qui-changent-la-vie-dun-dev-python/">requests ou path.py</a>, vous n&#8217;avez PAS besoin de tout cela. Vous jetez un coup d’œil à la doc, et vous faites 80% du boulot dans le shell, puis de temps à autre, vous vous référez à la documentation sur les points ambiguës. Je n&#8217;ai jamais du aller dans le code source de <code>requests</code>, je n&#8217;ai jamais eu besoin de comprendre <code>urllib</code> de fond en comble pour utiliser <code>requests</code>, et je n&#8217;ai pas besoin de connaître les subtilités de plusieurs paradigmes de programmation pour utiliser <code>requests</code>.</p>
<p>Alors oui, <code>requests</code> ne peut en aucun cas être comparé à Django en terme de taille et de couverture de besoin, et certes, en tant que professionnel averti, je suis tenu d&#8217;être capable de faire tout cela. Mais il y a quand même une énorme différence d&#8217;effort à fournir, et de qualification à avoir, pour l&#8217;usage de cette techno.</p>
<p>En prime, il est TRÈS difficile de débugger une CBV :</p>
<ul>
<li>Dans une vue générique sous forme de fonction, on peut juste faire <a href="http://sametmax.com/debugger-en-python-les-bases-de-pdb/">import ipdb</a>, et faire un step puis débugger tranquillement. Dans une CBV, vous le mettez où le break point ? Soit vous overridez une méthode (et il faut savoir par cœur laquelle), soit vous faites un wrapper provisoir sous forme de fonction (!), soit vous mettez le break cash dans le code source de la lib. C&#8217;est nul à chier, et improductif. Et certainement pas à la portée d&#8217;un débutant.</li>
<li>Les mixins ont un tas de comportements implicites, qu&#8217;il faut connaître pour comprendre pourquoi ceci fait cela. Et comme il y a généralement 3 ou 4 mixins (d&#8217;ailleurs, combien de dev peuvent donner la définition d&#8217;un mixin ?), et bien si il y a un problème, il y a 4 sources possibles. Qui héritent parfois d&#8217;autres classes, ce qui démultiplie le truc.</li>
<li>Quand ça plante le stack trace est blindée de références à droite et à gauche. Un putain de labyrinthe.</li>
</ul>
<p>Rajoutez à cela que la syntaxe est verbeuse comme c&#8217;est pas permis :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> get_context_data<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>:
    context = <span style="color: #008000;">super</span><span style="color: black;">&#40;</span>MaClass, <span style="color: #008000;">self</span><span style="color: black;">&#41;</span>.<span style="color: black;">get_context_data</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>
    context<span style="color: black;">&#91;</span><span style="color: #483d8b;">'ma_var'</span><span style="color: black;">&#93;</span> = <span style="color: #483d8b;">&quot;ma valeur&quot;</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> context</pre></div></div>

<p>Pour rajouter UNE variable dans le contexte ? Rhaaaaaaaaaaa. Je code en Python, pas en Java !</p>
<p>Et terminez sur le fait que pour utiliser tous les décorateurs codés depuis 5 ans, vous avez <a href="http://stackoverflow.com/questions/6069070/how-to-use-permission-required-decorators-on-django-class-based-views">une syntaxe bien pourrie</a> ou alors des <a href="https://github.com/lukaszb/django-guardian/issues/48">réimplementations complètes</a> sous forme de mixins. Yeah !</p>
<p>Vous comprendrez que ça me gonfle.</p>
<p>Tout ça pour quel gain ? Oui on gagne un peu en flexibilité, mais ça ne compense pas tout le reste, et ça ne permet en rien de faire des choses qu&#8217;on ne pouvait pas faire avant.</p>
<p>Je n&#8217;ai pas vu encore la moindre utilisation des CBV qui me fasse dire, &#8220;putain c&#8217;est tellement mieux qu&#8217;avant pour cette partie&#8221;. Ni aucune lib qui me fasse dire : &#8220;ouais, on aurait pas pu le faire aussi bien avec des vues sous forme de fonctions&#8221;.</p>
<p>Avec les CBV devenant la manière par défaut de coder les vues en Django, le framework devient beaucoup moins accessible au débutant, alors que sa facilité d&#8217;usage était un de ses points forts.</p>
<p>Bref, je suis de <a href="http://www.boredomandlaziness.org/2012/05/djangos-cbvs-are-not-mistake-but.html">l&#8217;avis de Nick Coghlan</a>, les CBV ne sont pas une erreur, elles ont leur utilité, mais balancer à la poubelle les vues sous forme de fonction est une vaste connerie.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=5976&amp;md5=2006171290b5ea019c93fdd3d4ba381e" title="Flattr" target="_blank"><img src="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://sametmax.com/des-annees-plus-tards-je-naime-toujours-pas-les-cbv/feed/</wfw:commentRss>
		<slash:comments>21</slash:comments>
		<atom:link rel="payment" title="Flattr this!" href="https://flattr.com/submit/auto?user_id=sam_et_max&amp;popout=1&amp;url=http%3A%2F%2Fsametmax.com%2Fdes-annees-plus-tards-je-naime-toujours-pas-les-cbv%2F&amp;language=en_GB&amp;category=text&amp;title=Des+ann%C3%A9es+plus+tard%2C+je+n%26%238217%3Baime+toujours+pas+les+CBV&amp;description=Les+Class+Based+Views+se+trouvent+maintenant+partout+en+Django.+Je+les+comprends+aujourd%26%238217%3Bhui+tr%C3%A8s+bien%2C+et+les+utilise+souvent+au+mieux.+Derni%C3%A8rement+j%26%238217%3Bai+d%C3%BB+utiliser+django-rest-framework%2C+une+tr%C3%A8s+belle...&amp;tags=cbv%2Cdjango%2Cpython%2Cblog" type="text/html" />
<enclosure url="http://sametmax.com/wp-content/uploads/2013/05/complots23.jpg" length="38284" type="image/jpg" />	</item>
		<item>
		<title>Il faut coucher utile</title>
		<link>http://sametmax.com/il-faut-coucher-utile/</link>
		<comments>http://sametmax.com/il-faut-coucher-utile/#comments</comments>
		<pubDate>Mon, 20 May 2013 08:10:40 +0000</pubDate>
		<dc:creator>Sam</dc:creator>
				<category><![CDATA[Cul]]></category>

		<guid isPermaLink="false">http://sametmax.com/?p=6098</guid>
		<description><![CDATA[Petit transcript, parce que j&#8217;adore rappeler que tous les avis sont dans la nature. Je déjeune avec une très ancienne amie d&#8217;enfance, chanteuse lyrique de métier, glamour, voir cul-cul, bobo bio récupérant ses meubles dans les poubelles, amatrice de chats, d&#8217;une grande gentillesse, le sourire tendre servi avec des tâches de rousseur. Bref, pas la [...]]]></description>
			<content:encoded><![CDATA[<p>Petit transcript, parce que j&#8217;adore rappeler que tous les avis sont dans la nature.</p>
<p>Je déjeune avec une très ancienne amie d&#8217;enfance, chanteuse lyrique de métier, glamour, voir cul-cul, bobo bio récupérant ses meubles dans les poubelles, amatrice de chats, d&#8217;une grande gentillesse, le sourire tendre servi avec des tâches de rousseur. Bref, pas la Paris Hilton de base.</p>
<p>Sam : &#8220;En fait tu considères que ta carrière décolle vraiment quand ? Quand tu n&#8217;as plus besoin de faire d&#8217;auditions ?&#8221;</p>
<p>Coraline : &#8220;Plutôt quand tu es payée ce que tu dois être payée pour ton travail. Les auditions, ça n&#8217;a rien à voir. Moi je galère toujours. Tu te souviens de mon amie Pascaline ? Celle qui a couché avec < Insérer ici le nom d'un grand ténor >. Dans la foulée elle a eu 3 auditions avec 3 des plus grandes maisons de Paris. Il faudrait que j&#8217;apprenne à faire comme elle.&#8221;</p>
<p>&#8220;Au moins vous les filles, vous pouvez faire ça. Nous on peut même pas coucher pour réussir.&#8221; (Sauf avec les gays, mais j&#8217;y ai pas pensé sur le coup. Remarque je devrais peut être tenter la cougar.)</p>
<p>&#8220;Attend, c&#8217;est le minimum. Déjà elle couche avec lui, c&#8217;est normal qu&#8217;il fasse quelque chose pour elle. Elle a pu se faire écouter par une agence qui m&#8217;a répondu qu&#8217;ils n&#8217;avaient plus le temps d&#8217;écouter personne. Comme ça, sur un coup de fil du mec. Moi je suis pour, hein. Si le mec te plaît pas, non, mais si il te plaît, y a pas de raison. J&#8217;avais un prof de chant qui me disait &#8216;Il faut coucher utile. Agréable, mais utile.&#8217;&#8221;</p>
<p>FEMA, où es-tu ?</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=6098&amp;md5=a595818f5b9aab715cde34ff16dba52c" title="Flattr" target="_blank"><img src="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://sametmax.com/il-faut-coucher-utile/feed/</wfw:commentRss>
		<slash:comments>20</slash:comments>
		<atom:link rel="payment" title="Flattr this!" href="https://flattr.com/submit/auto?user_id=sam_et_max&amp;popout=1&amp;url=http%3A%2F%2Fsametmax.com%2Fil-faut-coucher-utile%2F&amp;language=en_GB&amp;category=text&amp;title=Il+faut+coucher+utile&amp;description=Petit+transcript%2C+parce+que+j%26%238217%3Badore+rappeler+que+tous+les+avis+sont+dans+la+nature.+Je+d%C3%A9jeune+avec+une+tr%C3%A8s+ancienne+amie+d%26%238217%3Benfance%2C+chanteuse+lyrique+de+m%C3%A9tier%2C+glamour%2C+voir+cul-cul%2C+bobo...&amp;tags=blog" type="text/html" />
<enclosure url="http://sametmax.com/wp-content/uploads/2013/05/tumblr_mmy0npmfbS1r539hzo1_500.jpg" length="127695" type="image/jpg" />	</item>
		<item>
		<title>Nouvelle config iPython</title>
		<link>http://sametmax.com/nouvelle-config-ipython/</link>
		<comments>http://sametmax.com/nouvelle-config-ipython/#comments</comments>
		<pubDate>Sun, 19 May 2013 17:24:44 +0000</pubDate>
		<dc:creator>Sam</dc:creator>
				<category><![CDATA[Programmation]]></category>
		<category><![CDATA[ipython]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[shell]]></category>

		<guid isPermaLink="false">http://sametmax.com/?p=6158</guid>
		<description><![CDATA[J'ai bricolé une config pour iPython dernièrement. Rappelez-vous, on peut complètement <a href="http://sametmax.com/personnalisez-le-demarrage-dipython/">customiser ce shell</a>.

Voici ce que j'ai dans mon <em>./.config/ipython/profile_default/ipython_config.py</em>...]]></description>
			<content:encoded><![CDATA[<p>J&#8217;ai bricolé une config pour iPython dernièrement. Rappelez-vous, on peut complètement <a href="http://sametmax.com/personnalisez-le-demarrage-dipython/">customiser ce shell</a>.</p>
<p>Voici ce que j&#8217;ai dans mon <em>./.config/ipython/profile_default/ipython_config.py</em>:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">c.<span style="color: black;">TerminalIPythonApp</span>.<span style="color: black;">exec_lines</span> = <span style="color: black;">&#91;</span>
<span style="color: #483d8b;">'doctest_mode on'</span>,
<span style="color: #483d8b;">'from __future__ import unicode_literals, absolute_import, division'</span>,
<span style="color: #483d8b;">'import sys'</span>,
<span style="color: #483d8b;">'import os'</span>,
<span style="color: #483d8b;">'import re'</span>,
<span style="color: #483d8b;">'import json'</span>,
<span style="color: #483d8b;">'import base64'</span>,
<span style="color: #483d8b;">'import calendar'</span>,
<span style="color: #483d8b;">'import csv'</span>,
<span style="color: #483d8b;">'import datetime'</span>,
<span style="color: #483d8b;">'import itertools'</span>,
<span style="color: #483d8b;">'import random'</span>,
<span style="color: #483d8b;">'import hashlib'</span>,
<span style="color: #483d8b;">'import tempfile'</span>,
<span style="color: #483d8b;">'import argparse'</span>,
<span style="color: #483d8b;">'import math'</span>,
<span style="color: #483d8b;">'import random'</span>,
<span style="color: #483d8b;">'import subprocess'</span>,
<span style="color: #483d8b;">'from glob import glob'</span>,
<span style="color: #483d8b;">'from uuid import uuid4'</span>,
<span style="color: #483d8b;">'from datetime import datetime, timedelta'</span>,
<span style="color: #483d8b;">'from collections import Counter, OrderedDict'</span>,
<span style="color: #483d8b;">&quot;&quot;&quot;
def initial_imports():
&nbsp;
    # ne faites pas ça dans un code de prod :-)
    global path, relativedelta, requests 
&nbsp;
    print(&quot;<span style="color: #000099; font-weight: bold;">\\</span>nImported : 'sys', 'os', 're', 'json', 'base64', 'calendar', 'csv', 'datetime', 'itertools', 'random', 'hashlib', 'tempfile', 'argparse', 'math', 'random', 'glob', 'uuid4', 'datetime', 'timedelta', 'Counter', 'OrderedDict', 'subprocess'<span style="color: #000099; font-weight: bold;">\\</span>n&quot;)
&nbsp;
    try:
        from path import path
        print('Imported : &quot;path&quot;')
    except ImportError:
        print(&quot;'path' is not available&quot;)
&nbsp;
    try:
        from dateutil import relativedelta
        print('Imported : &quot;relativedelta&quot;')
    except ImportError:
        print(&quot;'dateutil' is not available&quot;)
&nbsp;
    try:
        import requests
        print('Imported : &quot;requests&quot;')
    except ImportError:
        print(&quot;'requests' is not available&quot;)
&nbsp;
    try:
        env = os.environ['VIRTUAL_ENV']
        print(&quot;<span style="color: #000099; font-weight: bold;">\\</span>nENV '{}'. You can import:<span style="color: #000099; font-weight: bold;">\\</span>n&quot;.format(os.path.basename(env)))
        cmd = subprocess.check_output([env + &quot;/bin/pip&quot;, &quot;freeze&quot;],
                                      stderr=subprocess.STDOUT).strip().split(&quot;<span style="color: #000099; font-weight: bold;">\\</span>n&quot;)
        p = re.compile(r'(^.*<span style="color: #000099; font-weight: bold;">\:</span><span style="color: #000099; font-weight: bold;">\s</span>)|((#|@).*$)|(==.*$)')
        print(&quot;'&quot; + &quot;', '&quot;.join(sorted(set(os.path.basename(p.sub('', f)) for f in cmd))) + &quot;'&quot;)
    except KeyError:
        pass
&nbsp;
    print('')
&quot;&quot;&quot;</span>,
<span style="color: #483d8b;">&quot;initial_imports()&quot;</span>
<span style="color: black;">&#93;</span></pre></div></div>

<p>Du coup, au démarrage d&#8217;iPython j&#8217;ai les bénéfices suivant :</p>
<ul>
<li>Comportement de Python 3 pour l&#8217;unicode, les imports et la division. Ils sont plus sains et facile à manipuler (plus besoin de préfixer de &#8216;u&#8217; les chaînes par exemple).</li>
<li>J&#8217;ai tout de suite sous la main une tonne de modules que j&#8217;utilise souvent sans avoir à les importer (os, datetime, random, etc).</li>
<li>J&#8217;importe aussi des modules optionnels (path, requests&#8230;).</li>
<li>Je sais si je suis dans un environnement virtuel, et si oui, ce qu&#8217;il y a installé dedans.</li>
</ul>
<p>Je vire aussi la bannière de démarrage :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">c.<span style="color: black;">TerminalIPythonApp</span>.<span style="color: black;">display_banner</span> = <span style="color: #008000;">False</span></pre></div></div>

<p>Et hop, mon affichage au démarrage ressemble à ça :</p>
<pre>$ ipython
Exception reporting mode: Plain
Doctest mode is: ON

Imported : 'sys', 'os', 're', 'json', 'base64', 'calendar', 'csv', 'datetime', 'itertools', 'random', 'hashlib', 'tempfile', 'argparse', 'math', 'random', 'glob', 'uuid4', 'datetime', 'timedelta', 'Counter', 'OrderedDict', 'subprocess'

'path' is not available
'dateutil' is not available
Imported : "requests"

ENV 'my_env'. You can import:

'BeautifulSoup', 'Django', 'Fabric', 'Jinja2', 'Pillow', 'Pygments', 'Sphinx', 'URLObject', 'Werkzeug', 'argparse', 'beautifulsoup4', 'colorlog', 'distribute', 'django-appconf', 'django-bootstrap-pagination', 'django-bootstrap-toolkit', 'django-compressor', 'django-debug-toolbar', 'django-extensions', 'django-guardian', 'django-loginas', 'django-model-utils', 'django-pdb', 'django-pytest', 'django-rest-framework.git', 'django-template-repl', 'docutils', 'easy-thumbnails', 'feedparser', 'gunicor
</pre>
<p>Ça fait un gros bloc visuellement, mais ça ne s&#8217;affiche qu&#8217;une fois, et le délai est acceptable.</p>
<p>Si j&#8217;ai besoin de l&#8217;info à nouveau, je peux toujours appeler :</p>

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

<p>Que ce genre de choses soient possibles et faciles me font adorer Python. La force du langage, ce n&#8217;est pas seulement son core, c&#8217;est tout son environnement, ses libs, ses outils qui gravitent autour qui rendent l&#8217;expérience de dev fantastique.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=6158&amp;md5=6eff89bdb98100a1faaf0fa4efa6d050" title="Flattr" target="_blank"><img src="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://sametmax.com/nouvelle-config-ipython/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		<atom:link rel="payment" title="Flattr this!" href="https://flattr.com/submit/auto?user_id=sam_et_max&amp;popout=1&amp;url=http%3A%2F%2Fsametmax.com%2Fnouvelle-config-ipython%2F&amp;language=en_GB&amp;category=text&amp;title=Nouvelle+config+iPython&amp;description=J%26%238217%3Bai+bricol%C3%A9+une+config+pour+iPython+derni%C3%A8rement.+Rappelez-vous%2C+on+peut+compl%C3%A8tement+customiser+ce+shell.+Voici+ce+que+j%26%238217%3Bai+dans+mon+.%2F.config%2Fipython%2Fprofile_default%2Fipython_config.py%3A+c.TerminalIPythonApp.exec_lines+%3D+%26%2391%3B+%27doctest_mode+on%27%2C+%27from+__future__+import+unicode_literals%2C...&amp;tags=ipython%2Cpython%2Cshell%2Cblog" type="text/html" />
<enclosure url="http://sametmax.com/wp-content/uploads/2013/05/5e4itlu.jpg" length="273612" type="image/jpg" />	</item>
		<item>
		<title>Qu&#8217;est-ce qu&#8217;un callable en Python ?</title>
		<link>http://sametmax.com/quest-ce-quun-callable-en-python/</link>
		<comments>http://sametmax.com/quest-ce-quun-callable-en-python/#comments</comments>
		<pubDate>Sat, 18 May 2013 07:05:36 +0000</pubDate>
		<dc:creator>Sam</dc:creator>
				<category><![CDATA[Programmation]]></category>
		<category><![CDATA[callable]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://sametmax.com/?p=1605</guid>
		<description><![CDATA[Un callable, qu'on peut traduire maladroitement par "appelable", est un objet qui peut être appelé. Et ça ne vous arrange pas beaucoup de savoir ça.

On parle de callable dans les tutos, les docs, etc, en supposant que vous savez ce que ça veut dire.

En fait c'est très simple, si vous pouvez mettre deux parenthèses après le nom d'un objet pour obtenir un effet, alors l'objet est un callable.
]]></description>
			<content:encoded><![CDATA[<p>Petit définition du jour.</p>
<p>Un callable, qu&#8217;on peut traduire maladroitement par &#8220;appelable&#8221;, est un objet qui peut être appelé. Et ça ne vous arrange pas beaucoup de savoir ça.</p>
<p>On parle de callable dans les tutos, les docs, etc, en supposant que vous savez ce que ça veut dire.</p>
<p>En fait c&#8217;est très simple, si vous pouvez mettre deux parenthèses après le nom d&#8217;un objet (en fait de la variable qui contient l&#8217;objet, mais ne chipotons pas) pour obtenir un effet, alors l&#8217;objet est un callable.</p>
<p>Une fonction est un callable:</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;">def</span> fonction<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
...     <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Vous m'avez appelé&quot;</span><span style="color: black;">&#41;</span>
...
<span style="color: #66cc66;">&gt;&gt;&gt;</span> fonction<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># appel de la fonction</span>
Vous m<span style="color: #483d8b;">'avez appelé</span></pre></div></div>

<p>Une classe est un callable:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> Class<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># appel de la classe</span>
<span style="color: #66cc66;">&lt;</span>__main__.<span style="color: black;">Class</span> <span style="color: #008000;">object</span> at 0x26d8310<span style="color: #66cc66;">&gt;</span></pre></div></div>

<p>Une méthode est un callable :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">class</span> Class<span style="color: black;">&#40;</span><span style="color: #008000;">object</span><span style="color: black;">&#41;</span>:
<span style="color: #ff7700;font-weight:bold;">def</span> methode<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
<span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Veuillez patientez, nous allons répondre à votre appel&quot;</span><span style="color: black;">&#41;</span>
...
<span style="color: #66cc66;">&gt;&gt;&gt;</span> obj = Class<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> obj.<span style="color: black;">methode</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># appel de la méthode</span>
Veuillez patientez, nous allons répondre à votre appel</pre></div></div>

<p>Il sont callables car on peut faire <code>()</code> dessus, et il se passe quelque chose. On peut les appeler.</p>
<p>Et par voie de conséquence, un callable peut <strong>retourner</strong> une valeur quand il est appelé. En fait, un callable est même garanti de retourner une valeur quand il est appelé, puisque toute fonction ou méthode retourne <code>None</code> par défaut en Python, et toute classe retourne au moins un objet vide.</p>
<p>Les string, les int, les listes, les fichiers ou les dicos ne sont pas des callables :</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: #ff4500;">1</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
Traceback <span style="color: black;">&#40;</span>most recent call last<span style="color: black;">&#41;</span>:
File <span style="color: #483d8b;">&quot;&lt;ipython-input-11-769e123a5ede&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: #ff4500;">1</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #008000;">TypeError</span>: <span style="color: #483d8b;">'int'</span> <span style="color: #008000;">object</span> <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #008000;">callable</span>
&nbsp;
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #483d8b;">&quot;&quot;</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
Traceback <span style="color: black;">&#40;</span>most recent call last<span style="color: black;">&#41;</span>:
File <span style="color: #483d8b;">&quot;&lt;ipython-input-12-de235e3e26d7&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: #483d8b;">&quot;&quot;</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #008000;">TypeError</span>: <span style="color: #483d8b;">'unicode'</span> <span style="color: #008000;">object</span> <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #008000;">callable</span>
&nbsp;
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
Traceback <span style="color: black;">&#40;</span>most recent call last<span style="color: black;">&#41;</span>:
File <span style="color: #483d8b;">&quot;&lt;ipython-input-13-bda5b10b5bf7&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: black;">&#91;</span><span style="color: black;">&#93;</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #008000;">TypeError</span>: <span style="color: #483d8b;">'list'</span> <span style="color: #008000;">object</span> <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #008000;">callable</span>
&nbsp;
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: black;">&#123;</span><span style="color: black;">&#125;</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
Traceback <span style="color: black;">&#40;</span>most recent call last<span style="color: black;">&#41;</span>:
File <span style="color: #483d8b;">&quot;&lt;ipython-input-14-67901a4bc3e8&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: black;">&#123;</span><span style="color: black;">&#125;</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #008000;">TypeError</span>: <span style="color: #483d8b;">'dict'</span> <span style="color: #008000;">object</span> <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #008000;">callable</span>
&nbsp;
<span style="color: #66cc66;">&gt;&gt;&gt;</span> f = <span style="color: #008000;">open</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'/etc/fstab'</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> f<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
Traceback <span style="color: black;">&#40;</span>most recent call last<span style="color: black;">&#41;</span>:
File <span style="color: #483d8b;">&quot;&lt;ipython-input-16-0ec059b9bfe1&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>
f<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #008000;">TypeError</span>: <span style="color: #483d8b;">'file'</span> <span style="color: #008000;">object</span> <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #008000;">callable</span></pre></div></div>

<p>Mais les classes (et oui, ce sont des classes, pas des fonctions malgré leurs noms en minuscule) <code>str</code>, <code>int</code>, <code>list</code>, <code>dict</code> et <code>file</code> sont des callables :</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;">int</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #ff4500;">0</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #008000;">str</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #483d8b;">''</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #008000;">dict</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: black;">&#123;</span><span style="color: black;">&#125;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #008000;">list</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #008000;">file</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'/etc/fstab'</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&lt;</span>open <span style="color: #008000;">file</span> u<span style="color: #483d8b;">'/etc/fstab'</span>, mode <span style="color: #483d8b;">'r'</span> at 0x2689930<span style="color: #66cc66;">&gt;</span></pre></div></div>

<p>En fait, la plupart des objets ne sont tout simplement pas des callables. Aucun nouvel objet n&#8217;est un callable par nature.</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> obj = Class<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #66cc66;">&gt;&gt;&gt;</span> obj<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
Traceback <span style="color: black;">&#40;</span>most recent call last<span style="color: black;">&#41;</span>:
File <span style="color: #483d8b;">&quot;&lt;ipython-input-18-da8742d08647&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>
obj<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #008000;">TypeError</span>: <span style="color: #483d8b;">'Class'</span> <span style="color: #008000;">object</span> <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #008000;">callable</span></pre></div></div>

<p>Donc, quand on vous dit de passer un &#8220;callable&#8221; en paramètre, généralement on vous dit de passer une fonction (sans les parenthèses), une classe (sans les parenthèses) ou une méthode (sans les parenthèses), afin de s&#8217;en servir comme <a href="http://sametmax.com/quest-ce-quun-callback/"><strong>call</strong>back</a>.</p>
<p>Par exemple, les champs des modèles Django acceptent un callable comme paramètre par défaut. Comme les callables sont garantis de retourner une valeur, Django utilise cela pour créer dynamiquement une valeur par défaut. La fonction <a href="http://sametmax.com/ordonner-en-python/">sort()</a> des listes accepte un callable en callback pour le paramètre key.</p>
<p>Demander un callable, c&#8217;est donc demander un truc qu&#8217;on peut appeler en utilisant des parenthèses, et qui va retourner un autre truc.</p>
<p>Au passage, pour votre culture, on peut créer ses propres callables. Ça sert rarement, dans quelques cas tordus. Il suffit de créer une classe avec la méthode magique <code>__call__</code>, et l&#8217;objet retourné sera automatiquement un callable :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">class</span> CreerUnCallable<span style="color: black;">&#40;</span><span style="color: #008000;">object</span><span style="color: black;">&#41;</span>:
...         <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__call__</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;">&quot;Vous m'avez appelé, maître ?&quot;</span>
...
<span style="color: #66cc66;">&gt;&gt;&gt;</span> un_callable = CreerUnCallable<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">print</span><span style="color: black;">&#40;</span>un_callable<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
Vous m<span style="color: #483d8b;">'avez appelé, maître ?</span></pre></div></div>

<p>On a donc ici DEUX callables : la classe, qui est callable par nature, et l&#8217;instance de la classe, qui est callable grâce à la méthode <code>__call__</code>.</p>
<p>Et moi j&#8217;ai commencé à taper cet article parce que je me suis dit que c&#8217;était une notion simple et que ça allait être vite fait, juste avant le petit dèj. Ca fait une heure que je suis dessus. Qu&#8217;est-ce que je suis con des fois.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=1605&amp;md5=0625590521663172fdd6453d170b7236" title="Flattr" target="_blank"><img src="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://sametmax.com/quest-ce-quun-callable-en-python/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		<atom:link rel="payment" title="Flattr this!" href="https://flattr.com/submit/auto?user_id=sam_et_max&amp;popout=1&amp;url=http%3A%2F%2Fsametmax.com%2Fquest-ce-quun-callable-en-python%2F&amp;language=en_GB&amp;category=text&amp;title=Qu%26%238217%3Best-ce+qu%26%238217%3Bun+callable+en+Python+%3F&amp;description=Petit+d%C3%A9finition+du+jour.+Un+callable%2C+qu%26%238217%3Bon+peut+traduire+maladroitement+par+%26%238220%3Bappelable%26%238221%3B%2C+est+un+objet+qui+peut+%C3%AAtre+appel%C3%A9.+Et+%C3%A7a+ne+vous+arrange+pas+beaucoup+de+savoir+%C3%A7a.+On...&amp;tags=callable%2Cpython%2Cblog" type="text/html" />
<enclosure url="http://sametmax.com/wp-content/uploads/2013/05/tumblr_mmuaqfKi1U1r539hzo1_500.jpg" length="63955" type="image/jpg" />	</item>
		<item>
		<title>Mise à jour</title>
		<link>http://sametmax.com/mise-a-jour/</link>
		<comments>http://sametmax.com/mise-a-jour/#comments</comments>
		<pubDate>Fri, 17 May 2013 22:49:15 +0000</pubDate>
		<dc:creator>Sam</dc:creator>
				<category><![CDATA[Philo et culture]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[meta]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://sametmax.com/?p=6146</guid>
		<description><![CDATA[Je le fais pas souvent mais quand je m'y met, je fais bien dans les coins.]]></description>
			<content:encoded><![CDATA[<p>J&#8217;ai mis à jour la liste des cours en <a href="http://sametmax.com/cours-et-tutos/les-articles-pour-apprendre-python-dans-le-bon-ordre/">Python</a> et <a href="http://sametmax.com/cours-et-tutos/les-articles-pour-apprendre-django-dans-le-bon-ordre/">Django</a>.</p>
<p>J&#8217;ai aussi updaté <a href="https://github.com/sametmax/miroir-du-blog/archive/master.zip">la copie offline du site</a> pour que vous puissiez en profiter dans le train, au camping, chez mamie, etc.</p>
<p>Enjoy.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=6146&amp;md5=68cd49405cb06f97ccd9b4dbac9b1ec9" title="Flattr" target="_blank"><img src="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://sametmax.com/mise-a-jour/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		<atom:link rel="payment" title="Flattr this!" href="https://flattr.com/submit/auto?user_id=sam_et_max&amp;popout=1&amp;url=http%3A%2F%2Fsametmax.com%2Fmise-a-jour%2F&amp;language=en_GB&amp;category=text&amp;title=Mise+%C3%A0+jour&amp;description=J%26%238217%3Bai+mis+%C3%A0+jour+la+liste+des+cours+en+Python+et+Django.+J%26%238217%3Bai+aussi+updat%C3%A9+la+copie+offline+du+site+pour+que+vous+puissiez+en+profiter+dans+le+train%2C+au...&amp;tags=django%2Cmeta%2Cpython%2Cblog" type="text/html" />
<enclosure url="http://sametmax.com/wp-content/uploads/2013/05/tumblr_mmy1lzZ2yN1r539hzo1_500.jpg" length="41189" type="image/jpg" />	</item>
		<item>
		<title>Les imports en Python</title>
		<link>http://sametmax.com/les-imports-en-python/</link>
		<comments>http://sametmax.com/les-imports-en-python/#comments</comments>
		<pubDate>Thu, 16 May 2013 09:13:27 +0000</pubDate>
		<dc:creator>Sam</dc:creator>
				<category><![CDATA[Programmation]]></category>
		<category><![CDATA[import]]></category>
		<category><![CDATA[module]]></category>
		<category><![CDATA[package]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://sametmax.com/?p=6127</guid>
		<description><![CDATA[Un jour vous avez du écrire votre propre module. Vous n'aviez pas vraiment réfléchi à la question. C'était juste une petite lib pour regrouper des fonctions. Ou juste une app Django. Un truc tout simple. Mais les imports ont soudainement cessé de devenir clairs. Ça ne marchait pas. Rien ne marchait. Vous aviez des <code>sys.path.append</code> partout juste au cas où et c'était encore pire.

Vous avez donc décidé de vous remettre à PHP, au moins le <code>include</code> utilise les chemins de fichiers, et ça, c'est facile.]]></description>
			<content:encoded><![CDATA[<p>Je suis fan de carmina burrana depuis l&#8217;age de 12 ans, alors pourquoi pas O Fortuna comme musique d&#8217;ambiance :</p>

<!-- iframe plugin v:2.3 - wordpress.org/extend/plugins/iframe/ -->
<iframe width="420" height="315" src="http://www.youtube.com/embed/nIwrgAnx6Q8" frameborder="0" scrolling="no" class="iframe-class"></iframe>
<p>Les imports, c&#8217;était fastoche. Vous étiez dans votre petit programme, et pour importer un module de la lib standard, vous faisiez:</p>

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

<p>Par exemple :</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;">os</span></pre></div></div>

<p>Et pour importer une classe ou une fonction de cette lib, vous faisiez :</p>

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

<p>Par exemple :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">from</span> hashlib <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">md5</span>
<span style="color: #ff7700;font-weight:bold;">from</span> <span style="color: #dc143c;">xml</span>.<span style="color: black;">etree</span> <span style="color: #ff7700;font-weight:bold;">import</span> Element</pre></div></div>

<p>Parfois, c&#8217;était un peu plus compliqué, mais ça allait encore. Des fois il fallait importer un sous-module :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">from</span> package.<span style="color: black;">sous_package</span> <span style="color: #ff7700;font-weight:bold;">import</span> module</pre></div></div>

<p>Par exemple :</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;">xml</span>.<span style="color: black;">sax</span> <span style="color: #ff7700;font-weight:bold;">import</span> saxutils</pre></div></div>

<p>Mais ça allait encore.</p>
<p>Et puis un jour vous avez du écrire votre propre module. Vous n&#8217;aviez pas vraiment réfléchi à la question. C&#8217;était juste une petite lib pour regrouper des fonctions. Ou juste une app Django. Un truc tout simple. Mais les imports ont soudainement cessé de devenir clairs. Ça ne marchait pas. Rien ne marchait. Vous aviez des <code>sys.path.append</code> partout juste au cas où et c&#8217;était encore pire.</p>
<p>Vous avez donc décidé de vous remettre à PHP, au moins le <code>include</code> utilise les chemins de fichiers, et ça, c&#8217;est facile.</p>
<h2>Sous le capot</h2>
<p>Quand vous utilisez <code>import</code>, sous le capot Python utilise le fonction <code>__import__</code>. Malgré ses <code>__</code> dans le nom, c&#8217;est une fonction ordinaire, et vous pouvez d&#8217;ailleurs l&#8217;utiliser vous-même :</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;">os</span> = <span style="color: #008000;">__import__</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'os'</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">join</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'s'</span>, <span style="color: #483d8b;">'ton'</span>, <span style="color: #483d8b;">'mon'</span>, <span style="color: #483d8b;">'g'</span><span style="color: black;">&#41;</span>
u<span style="color: #483d8b;">'s/ton/mon/g'</span></pre></div></div>

<p>En fait, importer un module, c&#8217;est créer un objet module qui est assigné à une variable tout à fait normale :</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;">type</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">os</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&lt;</span>type <span style="color: #483d8b;">'module'</span><span style="color: #66cc66;">&gt;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #dc143c;">os</span> = <span style="color: #483d8b;">&quot;on peut ecraser un module&quot;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>
Traceback <span style="color: black;">&#40;</span>most recent call last<span style="color: black;">&#41;</span>:
  File <span style="color: #483d8b;">&quot;&lt;ipython-input-12-e34748f24345&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;">os</span>.<span style="color: black;">path</span>
<span style="color: #008000;">AttributeError</span>: <span style="color: #483d8b;">'unicode'</span> <span style="color: #008000;">object</span> has no attribute <span style="color: #483d8b;">'path'</span>
&nbsp;
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">sys</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #008000;">type</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">sys</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&lt;</span>type <span style="color: #483d8b;">'module'</span><span style="color: #66cc66;">&gt;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #dc143c;">sys</span> = <span style="color: #483d8b;">&quot;je t'ecrase la tronche&quot;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #008000;">type</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">sys</span><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>Le mécanisme de module Python n&#8217;est donc pas un truc à part, c&#8217;est un objet comme le reste, qui contient des attributs. Les attributs sont les variables et les fonctions du module.</p>
<p>Pour charger un module, la fonction <code>__import__</code> passe par les étapes suivantes :</p>
<ol>
<li>Chercher si le module <code>os</code> existe.</li>
<li>Chercher si le module a déjà été importé. Si oui, s&#8217;arrêter ici et renvoyer le module existant.</li>
<li>Si non, chercher si il a été déjà compilé en .pyc.</li>
<li>Si ce n&#8217;est pas le cas, compiler le fichier .py en .pyc.</li>
<li>Charger le bytecode du fichier pyc.</li>
<li>Créer un objet module vide.</li>
<li>Éxecuter le bytecode dans le contexte de l&#8217;objet module et remplir ce dernier avec le résultat.</li>
<li>Ajouter l&#8217;objet module dans <code>sys.modules</code>, un dictionnaire qui contient tous les modules déjà chargés.</li>
<li>Retourner le module pour pouvoir l&#8217;assigner à une variable, par défaut la variable porte son nom.</li>
</ol>
<p>La fonction <code>__import__</code> est donc très complexe, et d&#8217;ailleurs si vous voulez l&#8217;utiliser pour des trucs plus compliqués qu&#8217;un simple import de module, vous allez galérer car sa signature est vraiment zarb.</p>
<p>Mais pour vous, seule l&#8217;étape 1 est importante à comprendre. C&#8217;est l&#8217;étape à laquelle tout se joue.</p>
<h2>Comment Python définit quel module importer ?</h2>
<p>C&#8217;est la partie vraiment difficile, en effet si un import ne marche pas, c&#8217;est très souvent parce que Python ne trouve pas le module que vous voulez. Et la raison pour laquelle il ne le trouve pas, c&#8217;est que vous ne comprenez pas comment il cherche.</p>
<p>Python utilise ce qu&#8217;on appelle le PYTHON PATH pour chercher les modules importables. C&#8217;est une variable système qui contient une liste de dossiers. Par exemple, sur ma machine, elle contient ceci :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: black;">&#91;</span><span style="color: #483d8b;">''</span>,
 <span style="color: #483d8b;">'/usr/bin'</span>,
 <span style="color: #483d8b;">'/usr/local/lib/python2.7/dist-packages/grin-1.2.1-py2.7.egg'</span>,
 <span style="color: #483d8b;">'/usr/lib/python2.7'</span>,
 <span style="color: #483d8b;">'/usr/lib/python2.7/plat-linux2'</span>,
 <span style="color: #483d8b;">'/usr/lib/python2.7/lib-tk'</span>,
 <span style="color: #483d8b;">'/usr/lib/python2.7/lib-old'</span>,
 <span style="color: #483d8b;">'/usr/lib/python2.7/lib-dynload'</span>,
 <span style="color: #483d8b;">'/home/sam/.local/lib/python2.7/site-packages'</span>,
 <span style="color: #483d8b;">'/usr/local/lib/python2.7/dist-packages'</span>,
 <span style="color: #483d8b;">'/usr/local/lib/python2.7/dist-packages/setuptools-0.6c11-py2.7.egg-info'</span>,
 <span style="color: #483d8b;">'/usr/lib/python2.7/dist-packages'</span>,
 <span style="color: #483d8b;">'/usr/lib/python2.7/dist-packages/PIL'</span>,
 <span style="color: #483d8b;">'/usr/lib/python2.7/dist-packages/gst-0.10'</span>,
 <span style="color: #483d8b;">'/usr/lib/python2.7/dist-packages/gtk-2.0'</span>,
 <span style="color: #483d8b;">'/usr/lib/pymodules/python2.7'</span>,
 <span style="color: #483d8b;">'/usr/lib/python2.7/dist-packages/ubuntu-sso-client'</span>,
 <span style="color: #483d8b;">'/usr/lib/python2.7/dist-packages/ubuntuone-client'</span>,
 <span style="color: #483d8b;">'/usr/lib/python2.7/dist-packages/ubuntuone-control-panel'</span>,
 <span style="color: #483d8b;">'/usr/lib/python2.7/dist-packages/ubuntuone-couch'</span>,
 <span style="color: #483d8b;">'/usr/lib/python2.7/dist-packages/ubuntuone-installer'</span>,
 <span style="color: #483d8b;">'/usr/lib/python2.7/dist-packages/ubuntuone-storage-protocol'</span>,
 <span style="color: #483d8b;">'/usr/lib/python2.7/dist-packages/wx-2.6-gtk2-unicode'</span>,
 <span style="color: #483d8b;">'/usr/lib/python2.7/dist-packages/IPython/extensions'</span><span style="color: black;">&#93;</span></pre></div></div>

<p> Donc, quand vous faites <code>import os</code>, Python va faire une boucle <code>for</code> là dessus et chercher dans chaque dossier si un package (un dossier avec un fichier <code>__init__.py</code>) ou un module (un fichier avec l&#8217;extension <em>.py</em>) nommé <code>os</code> existe.</p>
<p> Dès qu&#8217;il en trouve un, il s&#8217;arrête de chercher et l&#8217;importe. Si il n&#8217;en trouve pas, il va lever une <code>ImportError</code>.</p>
<p> Ce qui signifie que si votre module n&#8217;est PAS dans le PYTHON PATH, vous ne pouvez PAS l&#8217;importer. C&#8217;est impossible.</p>
<p> La grande majorité des problèmes d&#8217;import vient du fait que le module que vous essayez d&#8217;importer n&#8217;est pas dans le PYTHON PATH.</p>
<p> Maintenant, la grande question, c&#8217;est :</p>
<h2>Qu&#8217;est-ce qui est dans le PYTHON PATH ?</h2>
<p>Par défault, les dossiers <em>sites-packages</em> et <em>dist-packages</em> dans le dossier d&#8217;installation Python sont dans le PYTHON PATH. Quelques autres sont ajoutés selon les systèmes, mais vous pouvez toujours compter sur <em>sites-packages</em> et <em>dist-packages</em> pour être dans le PYTHON PATH. Quand vous installez une lib, par exemple avec <a href="http://sametmax.com/votre-python-aime-les-pip/">pip</a>, c&#8217;est là dedans que la lib va s&#8217;installer, pour être sûre de pouvoir être importée.</p>
<p>Quand vous êtes dans un <a href="http://sametmax.com/les-environnement-virtuels-python-virtualenv-et-virtualenvwrapper/">virtualenv</a>, les dossiers <em>sites-packages</em> et <em>dist-packages</em> de l&#8217;environnement virtuel sont ajoutés au PYTHON PATH.</p>
<p>Mais tout ça ne change pas grand chose pour vous. En effet, vous n&#8217;allez pas mettre VOTRE code dans les dossiers <em>sites-packages</em> et <em>dist-packages</em>.</p>
<p>C&#8217;est pour cela que Python possède un mécanisme supplémentaire : le dossier qui contient le module sur lequel vous lancez la commande <code>python</code> est automatiquement ajouté au PYTHON PATH.</p>
<h2>Le PYTHON PATH, en pratique</h2>
<p>Supposons que je sois dans le dossier <em>/home/sam/Bureau</em> et que j&#8217;aie dedans ce package. Voici à quoi ressemble mon arbo (<a href="https://github.com/sametmax/codes-des-articles/blob/master/2013/mai/test_imports.zip">téléchargez l&#8217;arbo vierge</a> pour vos tests):</p>
<pre><strong>/home/sam/Bureau # <-- je suis ici</strong>
.
`-- test_imports
    |-- __init__.py
    |-- package_tout_en_haut
    |   |-- __init__.py
    |   |-- autre_sous_package
    |   |   |-- __init__.py
    |   |   `-- autre_module_en_bas.py
    |   |-- sous_module.py
    |   `-- sous_package
    |       |-- __init__.py
    |       |-- autre_module_en_bas.py
    |       |-- autre_sous_package
    |       |   |-- __init__.py
    |       |   `-- autre_module_en_bas.py
    |       `-- module_tout_en_bas.py
    `-- top_module.py</pre>
<p>Si je lance un shell Python depuis ce dossier ou un script Python contenu dans ce dossier, je peux faire <code>import test_imports</code>, car <em>/home/sam/Bureau</em> est automatiquement ajouté au PYTHON PATH.</p>
<p>Je peux donc faire :</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> test_imports
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">from</span> test_imports <span style="color: #ff7700;font-weight:bold;">import</span> package_tout_en_haut
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">from</span> test_imports <span style="color: #ff7700;font-weight:bold;">import</span> top_module
test_imports.<span style="color: black;">top_module</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">from</span> test_imports.<span style="color: black;">package_tout_en_haut</span> <span style="color: #ff7700;font-weight:bold;">import</span> sous_module
test_imports.<span style="color: black;">package_tout_en_haut</span>.<span style="color: black;">sous_module</span></pre></div></div>

<p>Mais si je me mets ici dans <em>./package_tout_en_haut/sous_package</em> :</p>
<pre>/home/sam/Bureau
.
`-- test_imports
    |-- __init__.py
    |-- package_tout_en_haut
    |   |-- __init__.py
    |   |-- autre_sous_package
    |   |   |-- __init__.py
    |   |   `-- autre_module_en_bas.py
    |   |-- sous_module.py
    |   `-- <strong>sous_package     # <-- je suis ici</strong>
    |       |-- __init__.py
    |       |-- autre_module_en_bas.py
    |       |-- autre_sous_package
    |       |   |-- __init__.py
    |       |   `-- autre_module_en_bas.py
    |       |-- module_tout_en_bas.py
    `-- top_module.py</pre>
<p>Je ne peux PAS importer <code>test_imports</code>, ni dans un shell, ni depuis un module de ce dossier :</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> test_imports
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;">ImportError</span>: No module named test_imports</pre></div></div>

<p>En effet, comme je lance la commande Python depuis</p>
<p> <em>./package_tout_en_haut/sous_package</em></p>
<p> alors</p>
<p> <em>./package_tout_en_haut/sous_package</em> </p>
<p> <strong>EST</strong> ajouté au PYTHON PATH, mais </p>
<p> <em>/home/sam/Bureau/</em> </p>
<p> n&#8217;est <strong>PAS</strong> ajouté au PYTHON PATH.</p>
<p>Je ne peux donc PAS 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> test_imports <span style="color: #ff7700;font-weight:bold;">import</span> top_module</pre></div></div>

<p>depuis un fichier comme </p>
<p><em>.test_imports/package_tout_en_haut/sous_package/autre_module_en_bas.py</em> </p>
<p>et exécuter directement</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">python autre_module_en_bas.<span style="color: black;">py</span></pre></div></div>

<p>ni même</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">python ./test_imports/package_tout_en_haut/sous_package/autre_module_en_bas.<span style="color: black;">py</span></pre></div></div>

<p>Je peux 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> test_imports <span style="color: #ff7700;font-weight:bold;">import</span> top_module</pre></div></div>

<p>depuis </p>
<p><em>autre_module_en_bas.py</em> </p>
<p>uniquement si je lance un script Python tout en haut de mon arbo qui importe </p>
<p><em>autre_module_en_bas.py</em>.</p>
<h2>Mais alors, comment on fait ?<br />
</h2>
<p>Il faut s&#8217;assurer que le dossier qui contient <code>test_imports</code>, notre module racine, soit TOUJOURS dans le PYTHON PATH.</p>
<p>Il y a plusieurs possibilités pour cela.</p>
<p>La première, c&#8217;est que notre lib va être utilisée une fois installée avec pip. Dans ce cas, on s&#8217;en branle, <code>test_imports</code> sera dans sites-packages automatiquement, et on pourra faire <code>from test_imports import top_module </code> de partout joyeusement.</p>
<p>Mais souvent, ce n&#8217;est pas le cas, votre code n&#8217;est pas fait pour être installé.</p>
<p>La seconde technique consiste à s&#8217;assurer que l&#8217;on appelle TOUJOURS la commande Python depuis le dossier qui est tout au dessus. C&#8217;est ce que fait django avec sa commande <code>./manage.py</code> par exemple.</p>
<p>Vous avez votre projet :</p>
<pre>./manage.py
projet</pre>
<p>Et tout passe par <code>python manage.py</code>, qui est au dessus de projet, donc le dossier est bien ajouté au PYTHON PATH, et tout va bien.</p>
<p>Dans votre cas ça veut dire vous assurer qu&#8217;on lance toujours votre programme depuis un script d&#8217;entrée qui est tout en haut de votre arborescence.</p>
<p>Ca veut dire que vous devez avoir un point d&#8217;entrée UNIQUE pour votre package.</p>
<p>Mais parfois ça ne convient pas. Dans le cas des tests unitaires par exemple, il vous faut un point d&#8217;entrée spécialement pour les tests.</p>
<p>Pour ce genre de scénario, il faut donc avoir le dossier qui les contient <strong>à côté</strong> de votre package.  Ainsi, si j&#8217;avais des tests unitaires, je devrais faire un dossier <em>tests</em> à côté du dossier <em>test_imports</em>. Par exemple, transformer mon arbo en un truc comme ça :</p>
<pre>src
   |_ test_imports
   |_ tests
</pre>
<p>Afin que je lance les tests en faisant <code>python tests</code> depuis <em>src</em>. Et dans mes fichiers de tests, je pourrai faire des <code>from test_imports import truc</code>.</p>
<p>La manière dont vous organisez votre projet est donc très importante en Python, et si vous avez des problèmes d&#8217;import, la première chose à faire est de changer sa structure. Il n&#8217;y a pas de magie.</p>
<p>La dernière possibilité, quand tout a échoué, c&#8217;est de rajouter à la main le dossier dans le PYTHON PATH. <code>sys.path</code> est une simple liste, on peut donc faire un <code>append()</code> dessus.</p>
<p>Par exemple, si je veux absolument (mais je ne devrais pas :-)) pouvoir faire :</p>
<p><code>python .test_imports/package_tout_en_haut/sous_package/autre_module_en_bas.py</code> et importer <code>test_imports</code> dans <em>autre_module_en_bas.py</em>, je peux faire un truc du genre :</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;">os</span>
&nbsp;
dossier = <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">dirname</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">abspath</span><span style="color: black;">&#40;</span>__file__<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">while</span> <span style="color: #ff7700;font-weight:bold;">not</span> dossier.<span style="color: black;">endswith</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'test_imports'</span><span style="color: black;">&#41;</span>:
    dossier = <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">dirname</span><span style="color: black;">&#40;</span>dossier<span style="color: black;">&#41;</span>
&nbsp;
dossier = <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">dirname</span><span style="color: black;">&#40;</span>dossier<span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">if</span> dossier <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #dc143c;">sys</span>.<span style="color: black;">path</span>:
    <span style="color: #dc143c;">sys</span>.<span style="color: black;">path</span>.<span style="color: black;">append</span><span style="color: black;">&#40;</span>dossier<span style="color: black;">&#41;</span></pre></div></div>

<p>Ce code va remonter dans l&#8217;arbo jusqu&#8217;à tomber sur le chemin du dossier <em>test_imports</em> et ajouter son dossier parent au PYTHON PATH.</p>
<p>Ce n&#8217;est pas le truc le plus propre du monde, mais ça peut dépanner.</p>
<h2>Imports absolus et relatifs</h2>
<p>Si vous êtes dans <em>./package_tout_en_haut/sous_package</em> :</p>
<pre>/home/sam/Bureau
.
`-- test_imports
    |-- __init__.py
    |-- package_tout_en_haut
    |   |-- __init__.py
    |   |-- autre_sous_package
    |   |   |-- __init__.py
    |   |   `-- autre_module_en_bas.py
    |   |-- sous_module.py
    |   `-- <strong>sous_package     # <-- je suis ici</strong>
    |       |-- __init__.py
    |       |-- autre_module_en_bas.py
    |       |-- autre_sous_package
    |       |   |-- __init__.py
    |       |   `-- autre_module_en_bas.py
    |       |-- module_tout_en_bas.py
    |       `-- test_imports  # <-- autre package nommé test_imports
    |           `-- sous_module.py
    `-- top_module.py</pre>
<p>Vous voyez que vous avez deux packages nommés <em>test_imports</em>.</p>
<p>Si vous écrivez <code>import test_imports</code> dans <em>autre_module_en_bas.py</em>, que va-t-il se passer ?</p>
<p>C'est le module tout en bas qui va être importé.</p>
<p>Ce n'est pas forcément ce que vous voulez. Python 3 corrige cela en permettant des imports relatifs, et Python 2.7 peut en bénéficier en important tout en haut du module :</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> absolute_import</pre></div></div>

<p>En faisant cela, vous obtenez le comportement de Python 3 dans Python 2.7, et vous pourrez alors choisir entre faire :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> test_imports <span style="color: #808080; font-style: italic;"># importe le module tout en haut</span>
<span style="color: #ff7700;font-weight:bold;">import</span> .<span style="color: black;">test_imports</span> <span style="color: #808080; font-style: italic;"># import le module dans le même dossier</span>
<span style="color: #ff7700;font-weight:bold;">from</span> .<span style="color: black;">test_imports</span> <span style="color: #ff7700;font-weight:bold;">import</span> sous_module
<span style="color: #ff7700;font-weight:bold;">from</span> test_imports <span style="color: #ff7700;font-weight:bold;">import</span> top_module</pre></div></div>

<p>Je vous recommande de toujours utiliser <em>from __future__ import absolute_import</em>. Ca ne coûte rien, et c'est plus cohérent. Par contre, vous ne pourrez pas tester <em>from __future__ import absolute_import</em> dans le shell, donc cet exemple ne marche pas dans ipython, mais il fonctionne parfaitement dans vos modules.</p>
<p>On peut aussi faire des imports relatifs du package contenant avec :</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: #ff7700;font-weight:bold;">import</span> truc
<span style="color: #ff7700;font-weight:bold;">from</span> ..<span style="color: black;">package</span> <span style="color: #ff7700;font-weight:bold;">import</span> machin</pre></div></div>

<p>N'oubliez pas que ceci ne marche que :</p>
<ul>
<li>Si <code>from __future__ import absolute_import</code> est activé.</li>
<li>Le package tout en haut (celui qui contient tous les autres) est dans le PYTHON PATH</li>
</ul>
<p>Sinon, ça ne sert A RIEN. Ce n'est pas comme un <em>../</em> dans un bash. Ça ne remonte pas d'un dossier. C'est juste une notation pour dire j'utilise celui la plutôt que l'autre, quand il y a ambiguité.</p>
<h2>Pièges des imports</h2>
<h3>Package sans init</h3>
<p>Si vous avez :</p>
<pre>.
`-- test_imports
    |-- __init__.py
    |-- package_sans_init
    |   `-- nada.py</pre>
<p><em>nada.py</em> n'est pas importable, car <em>package_sans_init</em> ne contient pas de fichier <em>__init__.py</em>, même si <em>test_imports</em> est dans le PYTHON PATH. Ce comportement est corrigé en Python 3, et tout sous-dossier d'un package importable est automatiquement importable, qu'il contienne un <em>__init__.py</em> ou non.</p>
<h3>Imports circulaires</h3>
<p>J'en ai déjà parlé <a href="http://sametmax.com/quelques-erreurs-tordues-et-leurs-solutions-en-python/">ici</a>.</p>
<p>Vous avez :</p>
<pre>.
`-- test_imports
    |-- __init__.py
    |-- package_tout_en_haut
    |   |-- __init__.py
    |   `-- sous_package
    |       |-- __init__.py
    |       |-- autre_module_en_bas.py
    |       `-- module_tout_en_bas.py</pre>
<p>Et vous importez <code>autre_module_en_bas</code> dans <code>module_tout_en_bas</code> et inversement. Non seulement ça ne marchera pas, mais en plus l'erreur est déroutante :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #008000;">ImportError</span>: No module named module_tout_en_bas</pre></div></div>

<p>Oui vous avez bien lu, il va vous dire que le module n'existe pas !</p>
<p>Il n'y a pas non plus de solution propre à ce problème : soit vous fusionnez vos deux fichiers, soit vous faites un 3eme module qui utilise ces deux modules (et ces deux modules n'importent pas ce 3eme module).</p>
<p>Sinon il y a la solution crade : mettre un des imports dans un appel de fonction ou de méthode comme ça:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> truc<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">import</span> module_tout_en_bas
    module_tout_en_bas.<span style="color: black;">bidule</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Parfois, ça dépanne :-) On ne tue pas des chatons non plus, donc si ça ne devient pas une habitude, ça peut passer.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=6127&amp;md5=6dfcefd6dd5011b94280860d37ab983d" title="Flattr" target="_blank"><img src="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://sametmax.com/les-imports-en-python/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		<atom:link rel="payment" title="Flattr this!" href="https://flattr.com/submit/auto?user_id=sam_et_max&amp;popout=1&amp;url=http%3A%2F%2Fsametmax.com%2Fles-imports-en-python%2F&amp;language=en_GB&amp;category=text&amp;title=Les+imports+en+Python&amp;description=Je+suis+fan+de+carmina+burrana+depuis+l%26%238217%3Bage+de+12+ans%2C+alors+pourquoi+pas+O+Fortuna+comme+musique+d%26%238217%3Bambiance+%3A+Les+imports%2C+c%26%238217%3B%C3%A9tait+fastoche.+Vous+%C3%A9tiez+dans+votre+petit+programme%2C...&amp;tags=import%2Cmodule%2Cpackage%2Cpython%2Cblog" type="text/html" />
<enclosure url="http://sametmax.com/wp-content/uploads/2013/05/tumblr_mj4zt7GH891r539hzo1_500.jpg" length="77621" type="image/jpg" />	</item>
		<item>
		<title>Synchroniser son serveur avec ntp sous Linux</title>
		<link>http://sametmax.com/synchroniser-son-serveur-avec-ntp-sous-linux/</link>
		<comments>http://sametmax.com/synchroniser-son-serveur-avec-ntp-sous-linux/#comments</comments>
		<pubDate>Wed, 15 May 2013 07:32:53 +0000</pubDate>
		<dc:creator>Max</dc:creator>
				<category><![CDATA[Administration System]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[ntp]]></category>
		<category><![CDATA[serveur]]></category>
		<category><![CDATA[synchroniser]]></category>

		<guid isPermaLink="false">http://sametmax.com/?p=1086</guid>
		<description><![CDATA[Synchroniser son serveur avec l'heure sub-atomique de Sirus B en quelques clics...]]></description>
			<content:encoded><![CDATA[<p>NTP (Network Time Protocol) est un protocole utilisé pour synchroniser l&#8217;heure de votre système en utilisant un serveur en ligne. Cet article explique comment l&#8217;installer et le configurer sur un système d&#8217;exploitation Linux.</p>
<p><strong>1. Installation</strong></p>
<p>Pour installer le service ntp, ouvrez un terminal en root.</p>
<p><b>Sous Ubuntu:</b></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> ntp</pre></div></div>

<p><b><br />
2. Utilisation<br />
</b></p>
<p>La configuration de ntp se trouve généralement dans le fichier /etc/ntp.conf. On peut y ajouter de nouveaux serveurs de temps, en ajoutant une ligne similaire à celle-ci par exemple :</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">server <span style="color: #000000;">0</span>.fedora.pool.ntp.org dynamic</pre></div></div>

<p>Démarrez ensuite le service avec cette commande afin de synchroniser la date et l&#8217;heure (Attention, il faut plusieurs minutes avant que l&#8217;heure soit synchronisée) :</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><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>ntpd start</pre></div></div>

<p>On pourra ensuite vérifier que l&#8217;heure est correcte avec la commande &#8220;date&#8221;:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #7a0874; font-weight: bold;">&#91;</span>sm<span style="color: #000000; font-weight: bold;">@</span>web1 ~<span style="color: #7a0874; font-weight: bold;">&#93;</span><span style="color: #666666; font-style: italic;"># date</span>
Wed May <span style="color: #000000;">15</span> 07:<span style="color: #000000;">21</span>:<span style="color: #000000;">15</span> UTC <span style="color: #000000;">2013</span>
<span style="color: #7a0874; font-weight: bold;">&#91;</span>sm<span style="color: #000000; font-weight: bold;">@</span>web1 ~<span style="color: #7a0874; font-weight: bold;">&#93;</span><span style="color: #666666; font-style: italic;">#</span></pre></div></div>

<p>Note : en cas de problème, on pourra vérifier le bon fonctionnement avec la commande ntpstat qui donnera des informations sur le statut du service ntp :</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #7a0874; font-weight: bold;">&#91;</span>sm<span style="color: #000000; font-weight: bold;">@</span>web1 ~<span style="color: #7a0874; font-weight: bold;">&#93;</span><span style="color: #666666; font-style: italic;"># ntpstat</span>
synchronised to NTP server <span style="color: #7a0874; font-weight: bold;">&#40;</span>213.161.194.93<span style="color: #7a0874; font-weight: bold;">&#41;</span> at stratum <span style="color: #000000;">4</span>
<span style="color: #000000; font-weight: bold;">time</span> correct to within <span style="color: #000000;">562</span> ms
polling server every <span style="color: #000000;">64</span> s</pre></div></div>

<p><b>A quoi ça sert ?</b></p>
<p>Dans notre cas nous avons des sites qui hébergent du contenu avec des urls qui expirent au bout d&#8217;un certainstemps.<br />
La création de ces urls à durée de vie comptée est faite depuis le serveur web, le contenu se trouvant sur d&#8217;autres serveurs.<br />
ntp dans ce cas nous assure que tous les serveurs seront calés sur la même heure, ce qui évite de générer des urls déjà expirées si un des serveurs de contenu n&#8217;était pas à l&#8217;heure.</p>
 <p><a href="http://sametmax.com/?flattrss_redirect&amp;id=1086&amp;md5=5aabf1ac5ed68a01e3a317c1460fb923" title="Flattr" target="_blank"><img src="http://sametmax.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://sametmax.com/synchroniser-son-serveur-avec-ntp-sous-linux/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		<atom:link rel="payment" title="Flattr this!" href="https://flattr.com/submit/auto?user_id=sam_et_max&amp;popout=1&amp;url=http%3A%2F%2Fsametmax.com%2Fsynchroniser-son-serveur-avec-ntp-sous-linux%2F&amp;language=en_GB&amp;category=text&amp;title=Synchroniser+son+serveur+avec+ntp+sous+Linux&amp;description=NTP+%28Network+Time+Protocol%29+est+un+protocole+utilis%C3%A9+pour+synchroniser+l%26%238217%3Bheure+de+votre+syst%C3%A8me+en+utilisant+un+serveur+en+ligne.+Cet+article+explique+comment+l%26%238217%3Binstaller+et+le+configurer+sur+un...&amp;tags=linux%2Cntp%2Cserveur%2Csynchroniser%2Cblog" type="text/html" />
<enclosure url="http://sametmax.com/wp-content/uploads/2012/07/screenshot_86.jpg" length="53235" type="image/jpg" />	</item>
	</channel>
</rss>
