<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Mathieu Leplatre</title><link href="http://blog.mathieu-leplatre.info" rel="alternate"></link><link href="http://blog.mathieu-leplatre.info/feeds/all.atom.xml" rel="self"></link><id>http://blog.mathieu-leplatre.info</id><updated>2012-05-05T00:00:00+02:00</updated><entry><title>Serve your map layers with a usual Web hosting service</title><link href="http://blog.mathieu-leplatre.info/serve-your-map-layers-with-a-usual-web-hosting-service.html" rel="alternate"></link><updated>2012-05-05T00:00:00+02:00</updated><author><name>Mathieu Leplatre</name></author><id>http://blog.mathieu-leplatre.info/serve-your-map-layers-with-a-usual-web-hosting-service.html</id><summary type="html">&lt;p&gt;Someone asked me about serving map tiles from a basic Web host. I agreed
to reply with a blog post, since it completes the stories I've been telling
in my last &lt;a class="reference external" href="http://www.slideshare.net/makinacorpus/solutions-alternatives-google-maps-11501753"&gt;two&lt;/a&gt;
&lt;a class="reference external" href="/des-cartes-dun-autre-monde-la-suite-fr.html"&gt;talks&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;How to serve your map layers (&lt;em&gt;tiles&lt;/em&gt;) with the simplest Apache or nginx ?&lt;/p&gt;
&lt;div class="section" id="get-the-mbtiles-file"&gt;
&lt;h2&gt;Get the MBTiles file&lt;/h2&gt;
&lt;p&gt;We start from a tiles package (&lt;em&gt;MBTiles&lt;/em&gt;). Depending on where your layers come
from, you can either choose :&lt;/p&gt;
&lt;div class="section" id="to-publish-your-tilemill-map"&gt;
&lt;h3&gt;To publish your Tilemill map&lt;/h3&gt;
&lt;p&gt;Design your map in Tilemill, even &lt;a class="reference external" href="http://mapbox.com/tilemill/docs/guides/osm-bright-ubuntu-quickstart/"&gt;your own OpenStreetMap style customization&lt;/a&gt;,
and export it as MBTiles !
&lt;a class="reference external" href="http://mapbox.com/"&gt;MapBox hosting&lt;/a&gt; is the prefered solution, but you can still host and
serve your exported MBTiles file yourself !&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="to-mirror-a-wms-server"&gt;
&lt;h3&gt;To mirror a WMS server&lt;/h3&gt;
&lt;p&gt;Again, using &lt;a class="reference external" href="/landez-introducing-new-features-of-our-tiles-toolbox.html"&gt;landez&lt;/a&gt;, you can build a MBTiles
file from a WMS source (&lt;em&gt;orthophoto&lt;/em&gt;...), and then serve those layers yourself as tiles (at the speed of light !).&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="to-mirror-tiles-services"&gt;
&lt;h3&gt;To mirror tiles services&lt;/h3&gt;
&lt;p&gt;Using &lt;a class="reference external" href="/landez-introducing-new-features-of-our-tiles-toolbox.html"&gt;landez&lt;/a&gt;, you
can gather tiles from a tiles service, and package them in a &lt;tt class="docutils literal"&gt;.mbtiles&lt;/tt&gt;
file locally.&lt;/p&gt;
&lt;p&gt;If you plan on mirroring public tile services, do not forget to add attributions
and &lt;strong&gt;make sure it respects the terms of service&lt;/strong&gt;. Most services restrict bulk downloads &lt;a class="footnote-reference" href="#id3" id="id2"&gt;[1]&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="extract-files-on-disk"&gt;
&lt;h2&gt;Extract files on disk&lt;/h2&gt;
&lt;p&gt;Using &lt;a class="reference external" href="https://github.com/mapbox/mbutil"&gt;mbutil&lt;/a&gt;, we can extract the &lt;tt class="docutils literal"&gt;.mbtiles&lt;/tt&gt;
file into a destination folder.&lt;/p&gt;
&lt;p&gt;Unfortunately, the &lt;em&gt;pypi&lt;/em&gt; mirror is quite old, we'll install the last development version.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;wget https://github.com/mapbox/mbutil/zipball/master -O mbutil.zip
unzip mbutil
&lt;span class="nb"&gt;cd &lt;/span&gt;mapbox-mbutil*
sudo python setup.py install
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Done. Now extract. (&lt;em&gt;Note that the ``DEST`` folder must not exist&lt;/em&gt;) :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;mb-util --scheme&lt;span class="o"&gt;=&lt;/span&gt;osm FILE.mbtiles /path/to/DEST/
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If your MBTiles has an interaction layer (&lt;em&gt;UTFGrid&lt;/em&gt;), both &lt;tt class="docutils literal"&gt;.png&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;.json&lt;/tt&gt;
files will be expanded in folders.&lt;/p&gt;
&lt;p&gt;Just push the folder to your hosting, and you're done !&lt;/p&gt;
&lt;div class="section" id="cache-headers"&gt;
&lt;h3&gt;Cache headers&lt;/h3&gt;
&lt;p&gt;If you the master on board, tweak the cache headers :&lt;/p&gt;
&lt;p&gt;With &lt;em&gt;Apache&lt;/em&gt; :&lt;/p&gt;
&lt;pre class="literal-block"&gt;
ExpiresActive On
ExpiresDefault &amp;quot;access plus 7 days&amp;quot;
Alias /DEST /path/to/DEST/;
&lt;/pre&gt;
&lt;p&gt;With &lt;em&gt;nginx&lt;/em&gt; :&lt;/p&gt;
&lt;pre class="literal-block"&gt;
server {
    location /DEST {
        expires 7d;
        alias /path/to/DEST/;
    }
}
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="boost-with-subdomains"&gt;
&lt;h3&gt;Boost with subdomains&lt;/h3&gt;
&lt;p&gt;Browsers limit parallel downloads on the same domain. If you can declare
subdomains (&lt;em&gt;a.yourserver.org&lt;/em&gt;, &lt;em&gt;b.yourserver.org&lt;/em&gt;, ...), it will speed-up
tiles download.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="use-it-in-your-mapping-library"&gt;
&lt;h2&gt;Use it in your mapping library&lt;/h2&gt;
&lt;p&gt;With &lt;a class="reference external" href="http://leaflet.cloudmade.com"&gt;Leaflet&lt;/a&gt; for example :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;map&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;L&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;map&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addLayer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;L&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TileLayer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;http://{s}.yourserver.org/DEST/{z}/{x}/{y}.png&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;L&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;LatLng&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;43.60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.45&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Or &lt;a class="reference external" href="http://modestmaps.com"&gt;Modestmaps&lt;/a&gt; :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;provider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;MM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TemplatedLayer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;http://{s}.yourserver.org/DEST/{z}/{x}/{y}.png&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;map&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;MM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;map&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setCenter&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;lat&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;43.60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lon&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;1.45&lt;/span&gt;&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nx"&gt;setZoom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It will also work with interaction layers if you use &lt;a class="reference external" href="http://mapbox.com/wax/"&gt;Wax&lt;/a&gt; :)&lt;/p&gt;
&lt;table class="docutils footnote" frame="void" id="id3" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#id2"&gt;[1]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;MapBox &lt;a class="reference external" href="http://mapbox.com/tos/"&gt;strictly forbids&lt;/a&gt; proxying and further distribution of their tiles.
Bulk downloading from OpenStreetMap.org &lt;a class="reference external" href="http://wiki.openstreetmap.org/wiki/Tile_usage_policy#Bulk_Downloading"&gt;is strongly discouraged too&lt;/a&gt;.
And mass downloads &lt;a class="reference external" href="http://support.cloudmade.com/answers/offline-maps"&gt;cost money on Cloudmade&lt;/a&gt;.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
</summary><category term="tilemill"></category><category term="landez"></category><category term="mbutil"></category><category term="gis"></category></entry><entry><title>Simple and funky Web map printing</title><link href="http://blog.mathieu-leplatre.info/simple-and-funky-web-map-printing.html" rel="alternate"></link><updated>2012-05-02T00:00:00+02:00</updated><author><name>Mathieu Leplatre</name></author><id>http://blog.mathieu-leplatre.info/simple-and-funky-web-map-printing.html</id><summary type="html">&lt;p&gt;Strangely, users still insist in having Web page print capabilities, mostly to
share, export or archive what they see. Even if relevant permalinks are
often acceptable, we can't always dissuade them from printing :)&lt;/p&gt;
&lt;p&gt;And when it comes to Web maps, printing can be a nightmare ! Even though most of the time,
the needs involve a nice landscape PDF file with the map, a legend and the company logo.
For this, designing CSS print stylesheets and using the browser &lt;em&gt;print&lt;/em&gt; shortcut is not always
helpful.&lt;/p&gt;
&lt;p&gt;I present here a simple solution &lt;a class="footnote-reference" href="#id2" id="id1"&gt;[1]&lt;/a&gt; based on headless Webkit screenshots, permalinks,
SVG templates (&lt;em&gt;WYSIWYG&lt;/em&gt;), and PDF conversion.&lt;/p&gt;
&lt;div class="section" id="what-you-see-is-what-you-print"&gt;
&lt;h2&gt;What You See Is What You Print&lt;/h2&gt;
&lt;p&gt;In the following (short) video, we can see :&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;a map with dynamic content (&lt;em&gt;GeoJSON&lt;/em&gt;), bound to a form for attribute filtering and a legend
refreshed upon data ranges modifications ;&lt;/li&gt;
&lt;li&gt;a &lt;em&gt;Print&lt;/em&gt; button that delivers the current view as &lt;em&gt;PDF&lt;/em&gt; ;&lt;/li&gt;
&lt;li&gt;a landscape printout in which the map view, the legend, the filter form values were nicely inserted.&lt;/li&gt;
&lt;/ul&gt;
&lt;video id="webprint" width="560" controls="controls"&gt;
  &lt;source src="http://mathieu-leplatre.info/media/20120501-print.ogv" type="video/ogg" /&gt;
  Your browser does not support the video tag.
&lt;/video&gt;&lt;p&gt;(&lt;em&gt;BTW, small boo-boo in last screen: 'montain' instead of 'mountain'&lt;/em&gt;)&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="kids-you-can-do-this-at-home"&gt;
&lt;h2&gt;Kids, you can do this at home&lt;/h2&gt;
&lt;p&gt;Here is how we did it :&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;a Web page with a &amp;quot;stateful&amp;quot; permalink (&lt;em&gt;i.e. restore the map and page state using anchors, location hash, etc. ;&lt;/em&gt;).
Backbone.js &amp;amp; co. are meant for this ;&lt;/li&gt;
&lt;li&gt;A color scale built client-side from the resulting dataset, using &lt;a class="reference external" href="https://github.com/gka/chroma.js"&gt;Chroma.js&lt;/a&gt;,
to colorize the map items and populate the legend entries ;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://github.com/makinacorpus/django-screamshot"&gt;django-screamshot&lt;/a&gt;, a Web page
screenshot application, relying on &lt;a class="reference external" href="http://casperjs.org/"&gt;CasperJS&lt;/a&gt;. Spooky! ;&lt;/li&gt;
&lt;li&gt;a SVG landscape A4 document, edited with &lt;em&gt;Inkscape&lt;/em&gt;, as a Django template in which we placed simple tags (&lt;tt class="docutils literal"&gt;{{ filter.age_min }}&lt;/tt&gt;) for texts,
the &lt;tt class="docutils literal"&gt;{% base64capture %}&lt;/tt&gt; tag for the map screenshot, and a couple of arithmetics tags to
recreate a nice vectorial legend using the color scale entries;&lt;/li&gt;
&lt;li&gt;a Django view that receives the current page context (posted in &lt;em&gt;JS&lt;/em&gt;), renders the SVG (&lt;em&gt;will thus perform the screenshot&lt;/em&gt;),
and converts it to PDF ;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Quite straightforward, a couple of hours to put together, relatively easy
to deploy, obviously meet most users needs... these hacks are our happiness !&lt;/p&gt;
&lt;p&gt;If you want to know more about some missing parts, feel free to ask ! I could release stuff or just post some snippets...&lt;/p&gt;
&lt;table class="docutils footnote" frame="void" id="id2" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#id1"&gt;[1]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;from now on, I shall precise : even if it can cover most needs, it won't be adequate in all situations.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
</summary><category term="print"></category><category term="django"></category><category term="web"></category><category term="gis"></category><category term="django-screamshot"></category></entry><entry><title>Des cartes d'un autre monde, la suite</title><link href="http://blog.mathieu-leplatre.info/des-cartes-dun-autre-monde-la-suite-fr.html" rel="alternate"></link><updated>2012-04-18T00:00:00+02:00</updated><author><name>Mathieu Leplatre</name></author><id>http://blog.mathieu-leplatre.info/des-cartes-dun-autre-monde-la-suite-fr.html</id><summary type="html">&lt;div class="section" id="bravo-aux-organisateurs"&gt;
&lt;h2&gt;Bravo aux organisateurs !&lt;/h2&gt;
&lt;p&gt;L'édition 2012 des rencontres Django-fr a mis la barre très haut ! Ce fut un plaisir
de retrouver, ou rencontrer, autant de gens sympathiques et intéressants dans un cadre
aussi agréable :)&lt;/p&gt;
&lt;p&gt;Comme l'a souligné Olivier &lt;a class="footnote-reference" href="#id3" id="id1"&gt;[1]&lt;/a&gt;, cela va bien au delà de la techno qui fédère la communauté ;
les membres partagent aussi un esprit, une vision, des approches, qui transpassent
l'outil ! Agilité, pragmatisme, KISS, DRY, PEP20...&lt;/p&gt;
&lt;p&gt;Au menu, les problématiques de scaling étaient prédominantes, Django propulse des sites à
gros volume, comme &lt;em&gt;Liberation.fr&lt;/em&gt;, &lt;em&gt;20minutes.fr&lt;/em&gt;, &lt;em&gt;Mozilla&lt;/em&gt;, &lt;em&gt;Autolib&lt;/em&gt;, représentés
pendant ces rencontres, mais aussi &lt;em&gt;Instagram&lt;/em&gt;, &lt;em&gt;Lanyrd&lt;/em&gt;, &lt;em&gt;Disqus&lt;/em&gt;... autant d'expériences à partager!
Ce fut aussi un honneur d'accueillir deux invités nord-américains, python Lords chez &lt;em&gt;Heroku&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Cette année, je présentais une approche à contre-courant pour publier des données
cartographiques sur le Web :&lt;/p&gt;
&lt;blockquote&gt;
“ Comment publier des données cartographiques, aussi simplement qu'on
publie une image ? Il existe un monde où Django expose lui-même des
cartes interactives, sans déployer l'artillerie habituelle !
Une approche à contre-courant se prêtant parfaitement à la mise en
valeur quasi-immédiate d'informations geographiques, comme celles
libérées par votre ville ! ”&lt;/blockquote&gt;
&lt;iframe src="http://www.slideshare.net/slideshow/embed_code/12698176" width="560" height="432" frameborder="0" marginwidth="0" marginheight="0" scrolling="no"&gt;&lt;/iframe&gt;&lt;p&gt;&lt;strong&gt;Pour résumer&lt;/strong&gt; : éloignons-nous de l'OGC (WMS, WFS,...) quand il s'agit
juste de publier une carte sur une page Web.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="comment-rafraichir-les-cartes"&gt;
&lt;h2&gt;Comment rafraîchir les cartes ?&lt;/h2&gt;
&lt;p&gt;Je reprends une citation remontée par &lt;em&gt;twidi&lt;/em&gt; :&lt;/p&gt;
&lt;blockquote&gt;
“ There are only two hard things in Computer Science: cache invalidation and naming things ”
-- Phil Karlton&lt;/blockquote&gt;
&lt;p&gt;Selon la fréquence de rafraichissement de vos données, plusieurs stratégies sont
envisageables. Surtout qu'il est rare que l'ensemble de la carte nécessite d'être actualisé.&lt;/p&gt;
&lt;div class="section" id="en-generant-les-tuiles-en-temps-reel"&gt;
&lt;h3&gt;En générant les tuiles en temps réel&lt;/h3&gt;
&lt;p&gt;Comme l'expliquait Young Yahn &lt;a class="footnote-reference" href="#id4" id="id2"&gt;[2]&lt;/a&gt;, générer des tuiles en temps réel demande
d'avoir une architecture assez trappue et cela s'avère stressant à administrer.&lt;/p&gt;
&lt;p&gt;Cependant c'est possible avec des outils comme &lt;em&gt;tilelive&lt;/em&gt; ou &lt;em&gt;renderd&lt;/em&gt; (Apache &lt;em&gt;mod_tile&lt;/em&gt;).&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="avec-une-tache-planifiee"&gt;
&lt;h3&gt;Avec une tâche planifiée&lt;/h3&gt;
&lt;p&gt;Il faut trouver le compromis entre le temps de fabrication de la carte et la fréquence
de rafraichissement des données source.&lt;/p&gt;
&lt;p&gt;S'il s'agit de minutes, rafraichir la carte toutes les heures semble envisageable. La plupart du
temps, une fois par jour suffira.&lt;/p&gt;
&lt;p&gt;Il existe plusieurs outils, comme &lt;a class="reference external" href="/render-your-tilemill-stylesheets-with-landez.html"&gt;landez&lt;/a&gt;,
pour regénérer à intervales réguliers votre carte issue de &lt;em&gt;Tilemill&lt;/em&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="a-la-seconde"&gt;
&lt;h3&gt;À la seconde&lt;/h3&gt;
&lt;p&gt;Pour suivre une flotte de bateaux ou de véhicules, il faut que les éléments soient
déplacés en temps réel sur la carte.&lt;/p&gt;
&lt;p&gt;Il y a plusieurs outils très efficaces qui se reposent sur les Websockets. J'avais
fait l'application &lt;a class="reference external" href="/des-cartes-collaboratives-avec-livetitude-fr.html"&gt;Livetitude&lt;/a&gt;,
&lt;a class="reference external" href="http://vivid-warrior-6693.herokuapp.com"&gt;disponible en ligne&lt;/a&gt;, qui permet
d'éditer à plusieurs une carte de marqueurs, grace à &lt;em&gt;Pusher&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;La bibliothèque &lt;em&gt;Sharejs&lt;/em&gt;, issue du projet défunt Google Wave, permettrait d'aller
plus loin en faisant de l'édition collaborative d'attributs de géométries.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="en-fonction-de-filtres-ou-formulaires"&gt;
&lt;h3&gt;En fonction de filtres ou formulaires&lt;/h3&gt;
&lt;p&gt;Pour redessiner la carte en fonction de filtres, sur des attributs par exemple, l'utilisation
du format GeoJSON s'avère assez efficace.&lt;/p&gt;
&lt;p&gt;Votre serveur reçoit le formulaire, construit le jeu de données, et renvoie les
résultats (&lt;em&gt;Features = geometries + attributs&lt;/em&gt;).&lt;/p&gt;
&lt;p&gt;Cette approche peut s'avérer délicate selon la taille des jeux de données. Plusieurs
ruses existent afin de limiter le volume (ex: généralisation progressive selon la zone affichée)&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="carte-a-echelle-unique"&gt;
&lt;h2&gt;Carte à échelle unique&lt;/h2&gt;
&lt;p&gt;Parfois, pour certaines cartes, une seule vue suffit ! Nul besoin de zoomer, puisque le
phénomène intervient à une échelle en particulier !&lt;/p&gt;
&lt;p&gt;Pensez aux cartes des journaux ! Et vous serez séduits par l'excellent &lt;em&gt;Kartograph&lt;/em&gt;,
qui permet de publier des cartes sublimes facilement. Le SVG est manipulable en Javascript,
et permet d'ajouter des évènements sur les zones.&lt;/p&gt;
&lt;p&gt;Martin Dewulf a publié &lt;a class="reference external" href="http://migrationsmap.net"&gt;une jolie carte interactive à partir de données ouvertes&lt;/a&gt;.
Le résultat est très convaincaint, et sort de l'ordinaire.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="requiem-pour-les-trolls"&gt;
&lt;h2&gt;Requiem pour les trolls&lt;/h2&gt;
&lt;p&gt;La citation au début de la présentation, issue de &lt;em&gt;#whereconf&lt;/em&gt;, était volontairement
provocatrice. Mais de nombreux acteurs du Web et de la cartographie rejoignent
cette idée. Par exemple, entre temps, Sean Gillies a réitéré :&lt;/p&gt;
&lt;blockquote&gt;
“ How many MapBox and CartoDB like products would there be today if the
Open Source GIS community hadn't gone on a decade long WxS wander? “
-- &amp;#64;sgillies, 2012&lt;/blockquote&gt;
&lt;div class="section" id="oriente-communication"&gt;
&lt;h3&gt;Orienté communication&lt;/h3&gt;
&lt;p&gt;En 12 minutes, c'est très difficile de présenter tous les aspects, inconvénients
et avantages d'une approche à contre-courant !&lt;/p&gt;
&lt;p&gt;J'ai présenté le besoin plus simple de la cartographie sur le Web :&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;j'ai des données à caractère géographique ;&lt;/li&gt;
&lt;li&gt;je veux les afficher sur une page Web avec une carte interactive.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Le cas le plus simple, mais en même temps le plus répandu !&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="pas-toujours-d-alternatives-a-l-ogc"&gt;
&lt;h3&gt;Pas toujours d'alternatives à l'OGC&lt;/h3&gt;
&lt;p&gt;Dans certains contextes, les protocoles OGC sont indispensables :&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;interroperabilité entre systèmes hétérogènes sans médiation préalable (&lt;em&gt;serveurs externes, logiciels propriétaires, etc.&lt;/em&gt;);&lt;/li&gt;
&lt;li&gt;catalogage sémantique et syndication des jeux de données (&lt;em&gt;INSPIRE&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;construction d'une plateforme IDS&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;OpenLayers&lt;/em&gt; est la seule bibliothèque javascript qui a les reins assez solides pour
s'intégrer dans ces environnements.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="savoir-oublier-le-web"&gt;
&lt;h3&gt;Savoir oublier le Web&lt;/h3&gt;
&lt;p&gt;Il faut savoir juger la pertinence d'une application Web. Dans certaines situations,
le Web n'est pas la seule solution pour faire du client-server en multi-utilisateurs.&lt;/p&gt;
&lt;p&gt;L'année dernière par exemple, nous avons développé une application collaborative
pour manipuler des tronçons routiers. Nous avons &lt;a class="reference external" href="/merkopolo-a-simple-yet-powerful-starter-kit-for-your-qtc-gis-application.html"&gt;choisi C++/Qt&lt;/a&gt;,
avec PostGIS et des &lt;a class="reference external" href="/access-a-json-webservice-with-qt-c.html"&gt;webservices JSON&lt;/a&gt;,
parce que c'est ce qui se prêtait le mieux au besoin ! La même chose en &lt;em&gt;ExtJS&lt;/em&gt; aurait
été catastrophique !&lt;/p&gt;
&lt;iframe width="560" height="315" src="http://www.youtube.com/embed/7NPQo54NbJ8" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;&lt;table class="docutils footnote" frame="void" id="id3" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#id1"&gt;[1]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a class="reference external" href="https://twitter.com/#!/oloynet/status/192295759431995393"&gt;oloynet&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="id4" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#id2"&gt;[2]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a class="reference external" href="http://mapbox.com/blog/rendering-the-world/"&gt;Rendering the World, FOSS4G NA, 2012&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
</summary><category term="django"></category><category term="web"></category><category term="gis"></category><category term="livetitude"></category></entry><entry><title>Render your TileMill stylesheets with Landez</title><link href="http://blog.mathieu-leplatre.info/render-your-tilemill-stylesheets-with-landez.html" rel="alternate"></link><updated>2012-03-22T00:00:00+01:00</updated><author><name>Mathieu Leplatre</name></author><id>http://blog.mathieu-leplatre.info/render-your-tilemill-stylesheets-with-landez.html</id><summary type="html">&lt;p&gt;&lt;a class="reference external" href="http://mapbox.com/tilemill/"&gt;TileMill&lt;/a&gt; is an amazing tool to design your map, and publish it.
With &lt;a class="reference external" href="http://pypi.python.org/pypi/landez"&gt;landez&lt;/a&gt;, you can easily render it using python,
or do &lt;a class="reference external" href="/landez-introducing-new-features-of-our-tiles-toolbox.html"&gt;whatever comes with the API&lt;/a&gt; !&lt;/p&gt;
&lt;div class="section" id="from-tilemill-to-landez"&gt;
&lt;h2&gt;From TileMill to Landez&lt;/h2&gt;
&lt;p&gt;Use Tilemill to design your map, and export the &lt;a class="reference external" href="http://mapnik.org"&gt;Mapnik&lt;/a&gt; XML stylesheet :&lt;/p&gt;
&lt;img alt="images/tilemill-export-stylesheet.png" src="images/tilemill-export-stylesheet.png" /&gt;
&lt;p&gt;Then simply use &lt;em&gt;landez&lt;/em&gt; with &lt;tt class="docutils literal"&gt;stylefile&lt;/tt&gt; argument :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;logging&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;landez&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;MBTilesBuilder&lt;/span&gt;

&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;basicConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DEBUG&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;mb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MBTilesBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stylefile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Toulouse-Voirie.xml&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;toulouse-voirie.mbtiles&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;mb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_coverage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bbox&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;1.39&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;43.56&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;43.64&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                &lt;span class="n"&gt;zoomlevels&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;mb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In the above example, a &lt;em&gt;MBTiles&lt;/em&gt; file &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;toulouse-voirie.mbtiles&lt;/span&gt;&lt;/tt&gt; will be
created with all rendered tiles. (&lt;strong&gt;Note:&lt;/strong&gt; This won't render UTF-Grid tiles,
since TileMill does not expose this part in the XML stylesheet.)&lt;/p&gt;
&lt;p&gt;If you don't have Mapnik2 installed, you might encounter rendering errors
like : &lt;tt class="docutils literal"&gt;AssertionError: Cannot render tiles without mapnik !&lt;/tt&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="installation-of-mapnik-2"&gt;
&lt;h2&gt;Installation of Mapnik 2&lt;/h2&gt;
&lt;div class="section" id="mapnik2-packages-on-debian-ubuntu"&gt;
&lt;h3&gt;Mapnik2 packages on Debian/Ubuntu&lt;/h3&gt;
&lt;p&gt;In Ubuntu Precise (12.04) or Debian Wheezy (7.0), it's a piece of cake,
the package is available in the repos&lt;/p&gt;
&lt;pre class="literal-block"&gt;
sudo apt-get install python-mapnik2
&lt;/pre&gt;
&lt;p&gt;In Ubuntu Maverick (10.10), Natty (11.04), Oneiric (11.10), it's quite easy,
there is a PPA, from MapBox&lt;/p&gt;
&lt;pre class="literal-block"&gt;
sudo apt-add-repository ppa:developmentseed/mapbox
sudo update
sudo apt-get install python-mapnik2
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="mapnik2-and-python-bindings-from-sources"&gt;
&lt;h3&gt;Mapnik2 and python bindings from sources&lt;/h3&gt;
&lt;p&gt;Welcome in the quicksands of installing Mapnik2 python bindings from sources !&lt;/p&gt;
&lt;p&gt;&lt;a class="reference external" href="https://github.com/cspanring"&gt;Christian Spanring&lt;/a&gt; wrote a quick tutorial
to &lt;a class="reference external" href="https://gist.github.com/1314907"&gt;install it from sources on Ubuntu 10.04&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It might be a bit tricky to tweak this tutorial for your distribution. Hopefully, our
colleague &lt;a class="reference external" href="https://github.com/kiorky"&gt;Mathieu&lt;/a&gt; has prepared a &lt;a class="reference external" href="http://minitage.org"&gt;minitage's&lt;/a&gt; &amp;quot;&lt;em&gt;minilay&lt;/em&gt;&amp;quot; for it, &lt;a class="reference external" href="http://pypi.python.org/pypi/mapnik2#minitage"&gt;just follow the few steps&lt;/a&gt;
to compile the whole stack.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
</summary><category term="tilemill"></category><category term="landez"></category><category term="gis"></category><category term="howto"></category></entry><entry><title>Announcing Subtivals, realtime subtitles for film festivals</title><link href="http://blog.mathieu-leplatre.info/announcing-subtivals-realtime-subtitles-for-film-festivals.html" rel="alternate"></link><updated>2012-03-17T00:00:00+01:00</updated><author><name>Mathieu Leplatre</name></author><id>http://blog.mathieu-leplatre.info/announcing-subtivals-realtime-subtitles-for-film-festivals.html</id><summary type="html">&lt;img alt="images/subtivals-logo.png" src="images/subtivals-logo.png" /&gt;
&lt;div class="section" id="that-s-how-it-started"&gt;
&lt;h2&gt;That's how it started...&lt;/h2&gt;
&lt;p&gt;Subtitles and captions for the deaf and hard-of-hearing during film festivals
are rarely a priority, at least in France. Thus, most film copies are not
subtitled (except foreign movies shown in their original version).&lt;/p&gt;
&lt;p&gt;At the beginning of last year, &lt;a class="reference external" href="http://st2l.fr"&gt;my friend Lilian&lt;/a&gt; was promoting his project
of improving and facilitating the projection of subtitles during film festivals.
His activity consists in superimposing subtitles or projecting them on a
separate display below the screen.&lt;/p&gt;
&lt;img alt="images/subtivals-superimposed.png" class="align-center" src="images/subtivals-superimposed.png" /&gt;
&lt;p&gt;In this way, subtitling dissociates from the movie reel, unlike DVDs for example.
An operator is thence in charge of keeping captions synchroneous. It is sometimes called
&amp;quot;&lt;em&gt;virtual subtitling&lt;/em&gt;&amp;quot;; it is cheaper and easier than subtitled hard copies.&lt;/p&gt;
&lt;p&gt;Since there was no suitable Open Source tools to fulfill these precise needs,
&lt;a class="reference external" href="http://gedial.com"&gt;Arnaud&lt;/a&gt; and I gave him a hand. We developed &lt;a class="reference external" href="https://github.com/traxtech/subtivals"&gt;Subtivals&lt;/a&gt;,
a Free Software with simplicity and usuability for the technical operator in mind.&lt;/p&gt;
&lt;img alt="images/subtivals-screenshot.png" class="align-center" src="images/subtivals-screenshot.png" /&gt;
&lt;/div&gt;
&lt;div class="section" id="main-features"&gt;
&lt;h2&gt;Main features&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Subtivals&lt;/em&gt; has gained many features on the way, we released the &lt;strong&gt;version 1.0&lt;/strong&gt; last month,
after almost a year of development, driven by Lilian's experience.&lt;/p&gt;
&lt;p&gt;Among most notable features :&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Support of Advanced SubStation Alpha subtitles (ASS, *.ass) format&lt;/li&gt;
&lt;li&gt;Control Play / Pause / Delay / Speed&lt;/li&gt;
&lt;li&gt;Switch between several modes : timecode based, semi-automatic or fully manual&lt;/li&gt;
&lt;li&gt;Support for subtitles without timecodes (fixes duration automatically)&lt;/li&gt;
&lt;li&gt;SSA styles (italic, positions, colors)&lt;/li&gt;
&lt;li&gt;Customize and override styles (color and font size)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the small world of subtitles projection, where most tools are either
very expensive, or very archaic, &lt;em&gt;Subtivals&lt;/em&gt; is a revolution !&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="hall-of-fame"&gt;
&lt;h2&gt;Hall of fame&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Subtivals&lt;/em&gt; has proven its efficiency for several months now ! It was used
successfully in many film festivals (&lt;a class="reference external" href="http://www.festival-douarnenez.com"&gt;Festival de cinéma de Douarnenez&lt;/a&gt;,
&lt;a class="reference external" href="http://festival-galactique.infini.fr"&gt;Festival Intergalactique de Brest&lt;/a&gt;,
&lt;a class="reference external" href="http://www.festivaldebiarritz.com"&gt;Festival de Cinéma d'Amérique Latine de Biarritz&lt;/a&gt;,
&lt;a class="reference external" href="http://www.filmfestamiens.org"&gt;Festival International du film d'Amiens&lt;/a&gt;,
&lt;a class="reference external" href="http://www.lacinemathequedetoulouse.com/archives/2012/thematiques"&gt;Festival Zoom Arrière, 6e édition&lt;/a&gt;,
... and soon :
&lt;a class="reference external" href="http://www.cinelatino.com.fr"&gt;Cinélatino de Toulouse&lt;/a&gt;,
&lt;a class="reference external" href="http://festival-resistances.fr"&gt;Résistances à Foix&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;Its semi-manual mode also allows &lt;a class="reference external" href="http://en.wikipedia.org/wiki/Surtitle"&gt;surtitling&lt;/a&gt; at theaters (or opera, ballets, ...).&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="installation"&gt;
&lt;h2&gt;Installation&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Subtivals&lt;/em&gt; runs on GNU/Linux, Windows, Mac OS X and has no other external dependencies.&lt;/p&gt;
&lt;p&gt;On Ubuntu, install it easily using our PPA :&lt;/p&gt;
&lt;pre class="literal-block"&gt;
sudo add-apt-repository ppa:mathieu.leplatre/subtivals
sudo apt-get update &amp;amp;&amp;amp; sudo apt-get install subtivals
&lt;/pre&gt;
&lt;p&gt;Mac OS X and Windows installers are for sale, contact us !&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="contribute"&gt;
&lt;h2&gt;Contribute&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Subtivals&lt;/em&gt; is written in C++/Qt and released under the &lt;a class="reference external" href="http://www.gnu.org/copyleft/gpl.html"&gt;GNU General Public License&lt;/a&gt; .
It is available in English, French, Spanish and Catalan.&lt;/p&gt;
&lt;p&gt;If you feel like contributing, testing, translating... &lt;a class="reference external" href="https://github.com/traxtech/subtivals"&gt;join us on Github&lt;/a&gt; !&lt;/p&gt;
&lt;/div&gt;
</summary><category term="subtivals"></category><category term="subtitles"></category><category term="accessibility"></category><category term="qt"></category><category term="c++"></category></entry><entry><title>Django Handlebars.js integration</title><link href="http://blog.mathieu-leplatre.info/django-handlebarsjs-integration.html" rel="alternate"></link><updated>2012-03-17T00:00:00+01:00</updated><author><name>Mathieu Leplatre</name></author><id>http://blog.mathieu-leplatre.info/django-handlebarsjs-integration.html</id><summary type="html">&lt;p&gt;In order to write &lt;a class="reference external" href="http://handlebarsjs.com/"&gt;Handlebars.js&lt;/a&gt; templates
in &lt;a class="reference external" href="http://djangoproject.com"&gt;Django&lt;/a&gt; templates, I was gonna copy and paste for the second time
&lt;a class="reference external" href="https://gist.github.com/893408"&gt;Miguel Araujo's verbatim snippet&lt;/a&gt;.
But since one of the &lt;em&gt;Django&lt;/em&gt; weakness is the lack of reusable applications, I thought
I would package one instead :)&lt;/p&gt;
&lt;p&gt;The two existing django applications &lt;a class="footnote-reference" href="#id2" id="id1"&gt;[1]&lt;/a&gt; that integrate &lt;em&gt;Handlebars.js&lt;/em&gt; are somehow
bloated, they both kind of compile or render javascript templates on server-side &lt;em&gt;(sic)&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Oppositely, my &lt;a class="reference external" href="https://github.com/makinacorpus/django-templatetag-handlebars"&gt;django-templatetag-handlebars&lt;/a&gt; is very simple, you
write your &lt;em&gt;Handlebars&lt;/em&gt; template inside your &lt;em&gt;django&lt;/em&gt; template. &lt;em&gt;Django&lt;/em&gt;
will preserve nicely &lt;tt class="docutils literal"&gt;{}&lt;/tt&gt; tags, but still render &lt;tt class="docutils literal"&gt;{% %}&lt;/tt&gt; tags.&lt;/p&gt;
&lt;p&gt;For example, with this in your template :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;{% tplhandlebars &amp;quot;tpl-infos&amp;quot; %}
    {{total}} {% trans &amp;quot;result(s).&amp;quot; %}
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;{% trans &amp;quot;Min&amp;quot; %}: {{min}}&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;{% trans &amp;quot;Max&amp;quot; %}: {{max}}&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
{% endtplhandlebars %}
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The following block with end-up in your page :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;tpl-infos&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;text/x-handlebars-template&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    {{total}} result(s).
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Min: {{min}}&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Max: {{max}}&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Render it, client-side, as usual using &lt;em&gt;Handlebars&lt;/em&gt; API :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;properties&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;min&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;max&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;template&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Handlebars&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;#tpl-infos&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
    &lt;span class="nx"&gt;rendered&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;template&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Your rendered string is ready, and waiting to be inserted in your DOM :)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;10 result(s).
&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Min: 4&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Max: 5&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;a class="reference external" href="https://github.com/makinacorpus/django-templatetag-handlebars"&gt;Download and more info&lt;/a&gt;.&lt;/p&gt;
&lt;table class="docutils footnote" frame="void" id="id2" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#id1"&gt;[1]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;Both named &lt;em&gt;django-handlebars&lt;/em&gt;, &lt;a class="reference external" href="https://github.com/yavorskiy/django-handlebars"&gt;by Sergii Iavorskyi&lt;/a&gt; and &lt;a class="reference external" href="https://bitbucket.org/chrisv/django-handlebars"&gt;by Chris Vigelius&lt;/a&gt;.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
</summary><category term="django"></category><category term="javascript"></category><category term="handlebars"></category></entry><entry><title>landez : introducing new features of our tiles toolbox</title><link href="http://blog.mathieu-leplatre.info/landez-introducing-new-features-of-our-tiles-toolbox.html" rel="alternate"></link><updated>2012-02-24T12:45:00+01:00</updated><author><name>Mathieu Leplatre</name></author><id>http://blog.mathieu-leplatre.info/landez-introducing-new-features-of-our-tiles-toolbox.html</id><summary type="html">&lt;p&gt;&lt;a class="reference external" href="https://github.com/makinacorpus/landez"&gt;landez&lt;/a&gt; started as a very small toolbox to build MBTiles files
specifying bounding boxes and zoom levels. We have been using it for several GIS projects
at &lt;a class="reference external" href="http://www.makina-corpus.com"&gt;Makina Corpus&lt;/a&gt;, and can tell it's reliable !&lt;/p&gt;
&lt;p&gt;Landez is pure python and follows the &lt;a class="reference external" href="http://en.wikipedia.org/wiki/KISS_principle"&gt;KISS principle&lt;/a&gt;.
It has optional requirements on &lt;a class="reference external" href="http://pypi.python.org/pypi/PIL"&gt;PIL&lt;/a&gt; and &lt;a class="reference external" href="http://pypi.python.org/pypi/mapnik2"&gt;mapnik&lt;/a&gt;
for compositing, tile arranging or rendering.&lt;/p&gt;
&lt;p&gt;Recently, we've added many extra cool features, which deserve highlight !&lt;/p&gt;
&lt;div class="section" id="simple-wms-support"&gt;
&lt;h2&gt;Simple WMS support&lt;/h2&gt;
&lt;p&gt;With landez, you can store your WMS layers into MBTiles files ! It will
request the WMS images and save them into tiles on disk ! You can then
enjoy the power of MBTiles files : transport, speed, ...&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;mb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MBTilesBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wms_server&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://yourserver.com/geoserver/wms&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;wms_layers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;ign:departements&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                    &lt;span class="n"&gt;wms_options&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;image/png&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                     &lt;span class="n"&gt;transparent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                    &lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;dest.mbtiles&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;mb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_coverage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bbox&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;0.9853&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;43.6435&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1126&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;44.0639&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
                &lt;span class="n"&gt;zoomlevels&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;mb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="tiles-compositing"&gt;
&lt;h2&gt;Tiles compositing&lt;/h2&gt;
&lt;p&gt;This is the killer feature ! With landez, you can now merge multiple sources
of tiles (URL, WMS, MBTiles, Mapnik stylesheet) together !&lt;/p&gt;
&lt;p&gt;For example, build a new MBTiles file by blending tiles of another on top of OpenStreetMap tiles :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;mb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MBTilesBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;remote&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;merged.mbtiles&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;overlay&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TilesManager&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mbtiles_file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;carto.mbtiles&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;mb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_layer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;overlay&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;mb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Simply make a composite a WMS layer with OpenStreetMap using transparency ! You might find this useful
for compositing satellite image with street maps :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;mb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MBTilesBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wms_server&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://yourserver.com/geoserver/wms&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;wms_layers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;img:orthophoto&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                    &lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;wms_osm.mbtiles&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;overlay&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TilesManager&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;remote&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;mb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_layer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;overlay&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c"&gt;# 40%&lt;/span&gt;
&lt;span class="n"&gt;mb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="arrange-tiles-into-single-images"&gt;
&lt;h2&gt;Arrange tiles into single images&lt;/h2&gt;
&lt;p&gt;This feature can be very useful for printing tiled maps or have a quick overview
of your compositing results !&lt;/p&gt;
&lt;p&gt;Refer to any source of tiles, like you would do with &lt;cite&gt;MBTilesBuilder&lt;/cite&gt;,
add layers if you like and export the image !&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;ie&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ImageExporter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tiles_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;http://server/tile/{z}/{x}/{y}.png&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="n"&gt;ie&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;export_image&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bbox&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;180.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;90.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;180.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;90.0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="n"&gt;zoomlevel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;imagepath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;image.png&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="mbtiles-content-reading"&gt;
&lt;h2&gt;MBTiles content reading&lt;/h2&gt;
&lt;p&gt;landez can now read MBTiles content !&lt;/p&gt;
&lt;p&gt;We could proudly add it to the list of implementations for the &lt;a class="reference external" href="https://github.com/mapbox/mbtiles-spec/wiki/Implementations"&gt;MBTiles spec&lt;/a&gt;
and &lt;a class="reference external" href="https://github.com/mapbox/utfgrid-spec/wiki/Implementations"&gt;UTF-Grid spec&lt;/a&gt; !&lt;/p&gt;
&lt;p&gt;Use MBTiles files like any tile source :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;mb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MBTilesBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mbtiles_file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;yourfile.mbtiles&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;...extract single image or UTF-Grid tiles :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;landez.reader&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;MBTilesReader&lt;/span&gt;

&lt;span class="n"&gt;mbreader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MBTilesReader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;yourfile.mbtiles&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# Metadata&lt;/span&gt;
&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="n"&gt;mbreader&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="c"&gt;# Zoom levels&lt;/span&gt;
&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="n"&gt;mbreader&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;zoomlevels&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="c"&gt;# Image tile&lt;/span&gt;
&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;tile.png&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;wb&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="c"&gt;# UTF-Grid tile&lt;/span&gt;
&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;callback&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="next-steps"&gt;
&lt;h2&gt;Next steps...&lt;/h2&gt;
&lt;p&gt;The code has grown quickly and deserves a good refactoring, which is being done in a separate
branch &lt;a class="reference external" href="https://github.com/makinacorpus/landez"&gt;on GitHub&lt;/a&gt; ! The goal is to
keep the same simple API, better modularity, increase tests coverage...&lt;/p&gt;
&lt;p&gt;If you are wiling to participate, feel welcome !&lt;/p&gt;
&lt;/div&gt;
</summary><category term="python"></category><category term="mapbox"></category><category term="gis"></category><category term="landez"></category></entry><entry><title>TileMill on your Web server behind a reverse proxy</title><link href="http://blog.mathieu-leplatre.info/tilemill-on-your-web-server-behind-a-reverse-proxy.html" rel="alternate"></link><updated>2012-01-31T11:12:00+01:00</updated><author><name>Mathieu Leplatre</name></author><id>http://blog.mathieu-leplatre.info/tilemill-on-your-web-server-behind-a-reverse-proxy.html</id><summary type="html">&lt;p&gt;In the last version (0.9), &lt;a class="reference external" href="http://mapbox.com/tilemill/"&gt;TileMill&lt;/a&gt; has an additional dedicated process to
serve the tiles. We had to change some bits of our server configuration.&lt;/p&gt;
&lt;p&gt;Instead of documenting the new configuration in our internal Wiki,
I prefered to share here a few technical lines (quite rough though).&lt;/p&gt;
&lt;p&gt;We run TileMill inside a &lt;a class="reference external" href="/a-virtual-local-server-room-for-you-developper.html"&gt;virtual machine&lt;/a&gt; on a server with reverse proxy rules.&lt;/p&gt;
&lt;div class="section" id="reverse-proxy-configuration"&gt;
&lt;h2&gt;Reverse Proxy configuration&lt;/h2&gt;
&lt;p&gt;Assuming your reach your TileMill virtual machine at &lt;tt class="docutils literal"&gt;tilemill.sillywalk.loc&lt;/tt&gt;,
with its two processes running (ports &lt;tt class="docutils literal"&gt;20008&lt;/tt&gt; for tiles, &lt;tt class="docutils literal"&gt;20009&lt;/tt&gt; for the application),
your Apache reverse proxy configuration will be :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nt"&gt;&amp;lt;VirtualHost&lt;/span&gt; &lt;span class="err"&gt;*:80&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    ServerName tilemill.yourdomain.com

    ProxyPreserveHost On
    RewriteEngine on

    # Serve the tiles as /tiles/
    RewriteCond %{REQUEST_URI} ^(/tiles.*)$
    RewriteRule ^/tiles(.*) http://tilemill.sillywalk.loc:20008$1 [L,P]
    ProxyPassReverse /tiles http://tilemill.sillywalk.loc:20008/

    # Serve the application on /
    ProxyPass / http://tilemill.sillywalk.loc:20009/
    ProxyPassReverse / http://tilemill.sillywalk.loc:20009
&lt;span class="nt"&gt;&amp;lt;/VirtualHost&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="tilemill-configuration"&gt;
&lt;h2&gt;TileMill configuration&lt;/h2&gt;
&lt;p&gt;Now that tiles and application ports are reachable respectively on &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;http://tilemill.yourdomain.com/tiles&lt;/span&gt;&lt;/tt&gt;
and &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;http://tilemill.yourdomain.com/&lt;/span&gt;&lt;/tt&gt;, just tell TileMill to serve its pages accordingly in its configuration, &lt;tt class="docutils literal"&gt;/etc/tilemill/tilemill.config&lt;/tt&gt; :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="s2"&gt;&amp;quot;files&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;/usr/share/mapbox&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="s2"&gt;&amp;quot;server&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="s2"&gt;&amp;quot;coreUrl&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;tilemill.yourdomain.com:80&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="s2"&gt;&amp;quot;tileUrl&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;tilemill.yourdomain.com:80/tiles&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="s2"&gt;&amp;quot;port&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20009&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="s2"&gt;&amp;quot;listenHost&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;0.0.0.0&amp;quot;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Restart it...&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;sudo service tilemill restart
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Done !&lt;/p&gt;
&lt;/div&gt;
</summary><category term="tilemill"></category><category term="apache"></category><category term="howto"></category></entry><entry><title>Merkopolo : a simple yet powerful starter kit for your Qt/C++ GIS application</title><link href="http://blog.mathieu-leplatre.info/merkopolo-a-simple-yet-powerful-starter-kit-for-your-qtc-gis-application.html" rel="alternate"></link><updated>2012-01-26T11:30:00+01:00</updated><author><name>Mathieu Leplatre</name></author><id>http://blog.mathieu-leplatre.info/merkopolo-a-simple-yet-powerful-starter-kit-for-your-qtc-gis-application.html</id><summary type="html">&lt;p&gt;Recently, while the whole world looks completely hyped up with Web applications,
we chose to design and develop a desktop software in Qt/C++.&lt;/p&gt;
&lt;p&gt;Obviously, the choice was measured and justified ! We had to build a specific GIS application
with complex interactions and huge amounts of data, for a limited number of users.&lt;/p&gt;
&lt;p&gt;Quickly, we spotted &lt;a class="reference external" href="http://merkaartor.be/"&gt;Merkaartor&lt;/a&gt;, one of &lt;a class="reference external" href="http://wiki.openstreetmap.org/wiki/Editing"&gt;the official OpenStreetMap editors&lt;/a&gt;,
for its UI components and object model. And since we started to code, we never regretted this choice !&lt;/p&gt;
&lt;p&gt;C++ brings the power, Qt offers cross-platform and the compassion towards developers, and Merkaartor a lovely GIS flavour !&lt;/p&gt;
&lt;p&gt;We contributed to Merkaartor to give gits components a little bit of genericity, and
released &lt;a class="reference external" href="https://gitorious.org/merkopolo/merkopolo"&gt;Merkopolo&lt;/a&gt;, a Qt project
skeleton to handle dependencies and inclusion of base components.&lt;/p&gt;
&lt;p&gt;Here is what you immediately get once compiled :&lt;/p&gt;
&lt;img alt="images/merkopolo-preview.png" src="images/merkopolo-preview.png" /&gt;
&lt;p&gt;Now you can start coding serious stuff on top, with the Merkaartor components stack :&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Complete feature model with free attributes (tags)&lt;/li&gt;
&lt;li&gt;Custom drawing styles&lt;/li&gt;
&lt;li&gt;A variety of layers types (Tiles, WMS, Spatialite, GeoTIFF, GDAL...)&lt;/li&gt;
&lt;li&gt;Base classes for mouse interactions on map objects&lt;/li&gt;
&lt;li&gt;A projection system (&lt;em&gt;libproj&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;And even &lt;a class="reference external" href="postgis-data-in-c-using-gdal-and-qt.html"&gt;draw geometries from PostGIS database&lt;/a&gt; !&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a class="reference external" href="https://gitorious.org/merkopolo/merkopolo"&gt;Merkopolo is available on Gitorious&lt;/a&gt;.&lt;/p&gt;
</summary><category term="c++"></category><category term="gis"></category><category term="qt"></category><category term="merkopolo"></category><category term="merkartor"></category></entry><entry><title>Access a JSON webservice with Qt C++</title><link href="http://blog.mathieu-leplatre.info/access-a-json-webservice-with-qt-c.html" rel="alternate"></link><updated>2011-12-16T17:00:00+01:00</updated><author><name>Mathieu Leplatre</name></author><id>http://blog.mathieu-leplatre.info/access-a-json-webservice-with-qt-c.html</id><summary type="html">&lt;p&gt;&lt;em&gt;Original post at&lt;/em&gt; &lt;a class="reference external" href="http://makina-corpus.org"&gt;Makina Corpus&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Webservices are everywhere ! There are relevant in many situations, and
accessing them from your Qt C++ application is not an heresy.&lt;/p&gt;
&lt;p&gt;I will present here a very simple way to retrieve a JSON from a GET request.&lt;/p&gt;
&lt;div class="section" id="http-requests"&gt;
&lt;h2&gt;HTTP Requests&lt;/h2&gt;
&lt;p&gt;Using &lt;a class="reference external" href="http://developer.qt.nokia.com/doc/qt-4.7/qnetworkaccessmanager.html"&gt;QNetworkAccessManager&lt;/a&gt; is
a piece of cake :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;QNetworkAccessManager&lt;/span&gt; &lt;span class="n"&gt;networkManager&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;QUrl&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://gdata.youtube.com/feeds/api/standardfeeds/most_popular?v=2&amp;amp;alt=json&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;QNetworkRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;QNetworkReply&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;currentReply&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;networkManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// GET&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But, note that a slightly more generic approach would be to build the &lt;tt class="docutils literal"&gt;QUrl&lt;/tt&gt; from a parameters list :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;QUrl&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://gdata.youtube.com/feeds/api/standardfeeds/&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;QString&lt;/span&gt; &lt;span class="n"&gt;method&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;most_popular&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;QString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%1%2&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="n"&gt;QMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;QString&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;QVariant&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;alt&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;json&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;v&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;2&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;foreach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;QString&lt;/span&gt; &lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addQueryItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="parsing-json"&gt;
&lt;h2&gt;Parsing JSON&lt;/h2&gt;
&lt;p&gt;Get yourself a &lt;em&gt;slot&lt;/em&gt; to parse the &lt;tt class="docutils literal"&gt;QNetworkReply&lt;/tt&gt; :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;networkManager&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SIGNAL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;finished&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;QNetworkReply&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SLOT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;onResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;QNetworkReply&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;YourClass&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;onResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;QNetworkReply&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m_currentReply&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;QNetworkReply&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;NoError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// ...only in a blog post&lt;/span&gt;

    &lt;span class="n"&gt;QString&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;QString&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;reply&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;readAll&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="n"&gt;QScriptEngine&lt;/span&gt; &lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;QScriptValue&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;evaluate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="cm"&gt;/*&lt;/span&gt;
&lt;span class="cm"&gt;      Google YouTube JSON looks like this :&lt;/span&gt;

&lt;span class="cm"&gt;      {&lt;/span&gt;
&lt;span class="cm"&gt;        &amp;quot;version&amp;quot;: &amp;quot;1.0&amp;quot;,&lt;/span&gt;
&lt;span class="cm"&gt;        &amp;quot;encoding&amp;quot;: &amp;quot;UTF-8&amp;quot;,&lt;/span&gt;
&lt;span class="cm"&gt;        &amp;quot;feed&amp;quot;: {&lt;/span&gt;
&lt;span class="cm"&gt;          ..&lt;/span&gt;
&lt;span class="cm"&gt;          ..&lt;/span&gt;
&lt;span class="cm"&gt;          &amp;quot;entry&amp;quot;: [{&lt;/span&gt;
&lt;span class="cm"&gt;            &amp;quot;title&amp;quot;: {&lt;/span&gt;
&lt;span class="cm"&gt;                &amp;quot;$t&amp;quot;: &amp;quot;Nickelback- When We Stand Together&amp;quot;&lt;/span&gt;
&lt;span class="cm"&gt;            },&lt;/span&gt;
&lt;span class="cm"&gt;            &amp;quot;content&amp;quot;: {&lt;/span&gt;
&lt;span class="cm"&gt;                &amp;quot;type&amp;quot;: &amp;quot;application/x-shockwave-flash&amp;quot;,&lt;/span&gt;
&lt;span class="cm"&gt;                &amp;quot;src&amp;quot;: &amp;quot;http://www.youtube.com/v/76vdvdll0Y?version=3&amp;amp;f=standard&amp;amp;app=youtube_gdata&amp;quot;&lt;/span&gt;
&lt;span class="cm"&gt;            },&lt;/span&gt;
&lt;span class="cm"&gt;            &amp;quot;yt$statistics&amp;quot;: {&lt;/span&gt;
&lt;span class="cm"&gt;                &amp;quot;favoriteCount&amp;quot;: &amp;quot;29182&amp;quot;,&lt;/span&gt;
&lt;span class="cm"&gt;                &amp;quot;viewCount&amp;quot;: &amp;quot;41513706&amp;quot;&lt;/span&gt;
&lt;span class="cm"&gt;            },&lt;/span&gt;
&lt;span class="cm"&gt;            ...&lt;/span&gt;
&lt;span class="cm"&gt;            ...&lt;/span&gt;
&lt;span class="cm"&gt;          },&lt;/span&gt;
&lt;span class="cm"&gt;          ...&lt;/span&gt;
&lt;span class="cm"&gt;          ...&lt;/span&gt;
&lt;span class="cm"&gt;          ]&lt;/span&gt;
&lt;span class="cm"&gt;        }&lt;/span&gt;
&lt;span class="cm"&gt;      }&lt;/span&gt;
&lt;span class="cm"&gt;    */&lt;/span&gt;

    &lt;span class="c1"&gt;// Now parse this JSON according to your needs !&lt;/span&gt;
    &lt;span class="n"&gt;QScriptValue&lt;/span&gt; &lt;span class="n"&gt;entries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;property&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;feed&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;property&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;entry&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;QScriptValueIterator&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hasNext&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;QScriptValue&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="n"&gt;QString&lt;/span&gt; &lt;span class="n"&gt;link&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;property&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;content&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;property&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;src&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;viewCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;property&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;yt$statistics&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;property&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;viewCount&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;toInteger&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// Do something with those...&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That's it :)&lt;/p&gt;
&lt;p&gt;If you want more complexity, and don't mind adding extra-dependencies, check out Tomasz Siekierda's &lt;a class="reference external" href="http://gitorious.org/qwebservice"&gt;QtWebService&lt;/a&gt; !&lt;/p&gt;
&lt;/div&gt;
</summary><category term="c++"></category><category term="qt"></category><category term="json"></category></entry><entry><title>Remove django form field validation errors manually</title><link href="http://blog.mathieu-leplatre.info/remove-django-form-field-valiation-errors-manually.html" rel="alternate"></link><updated>2011-12-06T09:00:00+01:00</updated><author><name>Mathieu Leplatre</name></author><id>http://blog.mathieu-leplatre.info/remove-django-form-field-valiation-errors-manually.html</id><summary type="html">&lt;p&gt;&lt;em&gt;Original post at&lt;/em&gt; &lt;a class="reference external" href="http://www.makina-corpus.org"&gt;Makina Corpus&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Sometimes I look for something which seems so simple and stupid that I can't imagine
it does not exist. It makes me wonder why and who is the fool. Worse, I can't be sure about my search keywords to prove me anything.&lt;/p&gt;
&lt;p&gt;I just wanted to delete, reset or remove the validation errors of a single form field, within a django view, without
overriding the form or field class.&lt;/p&gt;
&lt;div class="section" id="a-one-liner"&gt;
&lt;h2&gt;A one-liner&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;aform&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;afield&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;aform&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;afield&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;error_class&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;That's it folks !&lt;/strong&gt;&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;This will not affect other fields errors or non-field errors ;&lt;/li&gt;
&lt;li&gt;This will reuse nicely the field error class (&lt;tt class="docutils literal"&gt;ErrorDict&lt;/tt&gt; or &lt;tt class="docutils literal"&gt;ErrorList&lt;/tt&gt;) ;&lt;/li&gt;
&lt;li&gt;You cannot set &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;aform.errors['afield']&lt;/span&gt; = None&lt;/tt&gt; or your form &lt;tt class="docutils literal"&gt;full_clean()&lt;/tt&gt; will be performed again !&lt;/li&gt;
&lt;li&gt;Obviously, the ideal approach is to override your form &lt;tt class="docutils literal"&gt;clean()&lt;/tt&gt; properly.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
</summary><category term="django"></category><category term="tips"></category></entry><entry><title>An equivalent of Django's select_related for ManyToMany and OneToMany relationships</title><link href="http://blog.mathieu-leplatre.info/django-selectrelated-manytomany.html" rel="alternate"></link><updated>2011-12-05T11:09:00+01:00</updated><author><name>Mathieu Leplatre</name></author><id>http://blog.mathieu-leplatre.info/django-selectrelated-manytomany.html</id><summary type="html">&lt;p&gt;&lt;em&gt;Original post at&lt;/em&gt; &lt;a class="reference external" href="http://makina-corpus.org"&gt;Makina Corpus&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Using an ORM simplifies and reduces greatly the amount of code to interact with databases.
Nevertheless, it can easily hide database design defects or become a source of serious performance issues.&lt;/p&gt;
&lt;div class="section" id="a-common-pitfall"&gt;
&lt;h2&gt;A Common Pitfall&lt;/h2&gt;
&lt;p&gt;With Django, the most classic problem occurs while accessing objects relations attributes
inside a loop. That's why QuerySet's method &lt;tt class="docutils literal"&gt;select_related()&lt;/tt&gt; exists :
it will join specified relations so that access to their attributes does not hit the database.
&lt;a class="reference external" href="https://docs.djangoproject.com/en/dev/ref/models/querysets/#select-related"&gt;Refer to Django's documentation&lt;/a&gt; for more information !&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="one-to-many-and-many-to-many-relationships"&gt;
&lt;h2&gt;One-To-Many and Many-To-Many Relationships&lt;/h2&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;select_related()&lt;/tt&gt; is not able to follow One-To-Many (&lt;em&gt;1-n&lt;/em&gt;) and Many-To-Many (&lt;em&gt;n-n&lt;/em&gt;) relationships.
The Django team is currently working on &lt;tt class="docutils literal"&gt;prefetch_related()&lt;/tt&gt;. But before we can enjoy this
future feature, we can implement an equivalent in python.&lt;/p&gt;
&lt;p&gt;With these models :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Pizza&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CharField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Restaurant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CharField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;pizzas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ManyToManyField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Pizza&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;through&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;PizzaRestaurant&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PizzaRestaurant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;pizza&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ForeignKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Pizza&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;restaurant&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ForeignKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Restaurant&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FloatField&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This loop will generate &lt;em&gt;1 + N&lt;/em&gt; queries :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;restaurant&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;Restaurant&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;all&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;pizza&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;restaurant&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pizzas&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;all&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="n"&gt;pizza&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Whereas this one will &lt;strong&gt;only&lt;/strong&gt; generate &lt;em&gt;2&lt;/em&gt; queries :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c"&gt;# Store relationships in a dict&lt;/span&gt;
&lt;span class="n"&gt;byrestaurant&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;pr&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;PizzaRestaurant&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;select_related&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;restaurant&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;pizza&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;all&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;byrestaurant&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setdefault&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;restaurant&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pizza&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c"&gt;# Use stored lists&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;restaurant&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;Restaurant&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;all&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;pizza&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;byrestaurant&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;restaurant&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="n"&gt;pizza&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;According to the amount of &lt;em&gt;N&lt;/em&gt;, doing that trick in views can boost your pages !&lt;/p&gt;
&lt;p&gt;This is not perfect and elegant, but if it allows you to downsize the number of queries
from several thousands to fifteen, like &lt;a class="reference external" href="http://gitorious.org/memopol2-0/memopol2-0/merge_requests/18"&gt;it did on Memopol2&lt;/a&gt;, you can think twice.&lt;/p&gt;
&lt;/div&gt;
</summary><category term="django"></category><category term="performance"></category></entry><entry><title>Des cartes collaboratives avec Livetitude</title><link href="http://blog.mathieu-leplatre.info/des-cartes-collaboratives-avec-livetitude-fr.html" rel="alternate"></link><updated>2011-11-23T14:00:00+01:00</updated><author><name>Mathieu Leplatre</name></author><id>http://blog.mathieu-leplatre.info/des-cartes-collaboratives-avec-livetitude-fr.html</id><summary type="html">&lt;p&gt;&lt;em&gt;Article original publié chez&lt;/em&gt; &lt;a class="reference external" href="http://makina-corpus.org"&gt;Makina Corpus&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Cela fait plusieurs semaines que je voulais présenter ma petite application
de partage de cartes, dont je me sers déjà comme alternative aux marqueurs de Google Maps.&lt;/p&gt;
&lt;div class="section" id="en-bref"&gt;
&lt;h2&gt;En bref&lt;/h2&gt;
&lt;p&gt;&lt;a class="reference external" href="https://github.com/makinacorpus/livetitude"&gt;Livetitude&lt;/a&gt; est un outil Web pour créer des cartes de manière collaborative
&lt;strong&gt;en temps réel&lt;/strong&gt; (à la manière d'un &lt;a class="reference external" href="http://fr.wikipedia.org/wiki/EtherPad"&gt;pad&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Fonctionnant sur des terminaux mobiles, Livetitude permet également de partager la position des collaborateurs de la carte,
d'exporter les données au format GeoJSON ou de publier la carte sur une page Web.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="sous-le-capot"&gt;
&lt;h2&gt;Sous le capot&lt;/h2&gt;
&lt;p&gt;J'ai pris du plaisir à hacker cette application, elle tire profit
d'outils très simples mais très efficaces :&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://http://leaflet.cloudmade.com"&gt;Leaflet&lt;/a&gt; pour afficher les cartes ;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://pusher.com"&gt;Pusher&lt;/a&gt; (Websockets) pour la collaboration en temps réel ;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://couchdb.apache.org/"&gt;CouchDB&lt;/a&gt; pour stocker les données ;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://flask.pocoo.org"&gt;Flask&lt;/a&gt; pour servir les pages ;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://www.heroku.com"&gt;Heroku&lt;/a&gt; pour héberger l'application.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Bien entendu, le code source est libre et disponible sur &lt;a class="reference external" href="https://github.com/makinacorpus/livetitude"&gt;le GitHub de Makina Corpus&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="utilisation"&gt;
&lt;h2&gt;Utilisation&lt;/h2&gt;
&lt;p&gt;Une instance est &lt;a class="reference external" href="http://vivid-warrior-6693.herokuapp.com/"&gt;déployée en ligne&lt;/a&gt;, dans le cloud d'Heroku,
dont vous pouvez vous servir, &lt;em&gt;pour une utilisation en bon père de famille&lt;/em&gt; :)&lt;/p&gt;
&lt;p&gt;Les marqueurs peuvent contenir du texte ou de l'HTML, et aucune donnée de localisation des visiteurs n'est stockée.&lt;/p&gt;
&lt;img alt="images/livetitude-poc.png" src="images/livetitude-poc.png" /&gt;
&lt;div class="section" id="comment-publier-vos-donnees-existantes"&gt;
&lt;h3&gt;Comment publier vos données existantes ?&lt;/h3&gt;
&lt;p&gt;Si vous souhaitez publier et visualiser vos marqueurs sur une carte de Livetitude,
il suffit de poster (&lt;tt class="docutils literal"&gt;POST&lt;/tt&gt;) les coordonnées de vos points sur l'URL &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;http://server/&amp;lt;CARTE&amp;gt;/add&lt;/span&gt;&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;Par exemple, avec une petite fonction python :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;httplib&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;urllib&lt;/span&gt;

&lt;span class="n"&gt;SERVER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;server&amp;quot;&lt;/span&gt;  &lt;span class="c"&gt;# e.g. vivid-warrior-6693.herokuapp.com&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mapname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;coords&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;/&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s"&gt;/add&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;mapname&lt;/span&gt;
    &lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="s"&gt;&amp;#39;coords&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;coords&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="s"&gt;&amp;#39;data&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="s"&gt;&amp;#39;classid&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;  &lt;span class="c"&gt;# (=color)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;urlencode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Content-type&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;application/x-www-form-urlencoded&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="s"&gt;&amp;quot;Accept&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;text/plain&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;conn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;httplib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HTTPConnection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SERVER&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;POST&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getresponse&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;


&lt;span class="n"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;PasLoin&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;10.1,54.9&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Super resto!&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;PasLoin&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;19.4,65.1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Bon mojito&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Les points sont alors visibles en ligne sur &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;http://server/PasLoin&lt;/span&gt;&lt;/tt&gt; ou
disponible en GeoJSON sur &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;http://server/PasLoin/points&lt;/span&gt;&lt;/tt&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="contribuer"&gt;
&lt;h2&gt;Contribuer&lt;/h2&gt;
&lt;p&gt;Livetitude est une application très simple, à l'état de preuve de concept. Mais
le code source est très réduit et donc très rapide à prendre en main !&lt;/p&gt;
&lt;p&gt;Toutes vos &lt;a class="reference external" href="https://github.com/makinacorpus/livetitude/issues"&gt;suggestions ou contributions&lt;/a&gt; sont les bienvenues !&lt;/p&gt;
&lt;/div&gt;
</summary><category term="maps"></category><category term="gis"></category><category term="websockets"></category><category term="leaflet"></category><category term="heroku"></category></entry><entry><title>Git : annuler proprement un commit après un push</title><link href="http://blog.mathieu-leplatre.info/git-annuler-proprement-un-commit-apres-un-push-fr.html" rel="alternate"></link><updated>2011-11-03T14:15:00+01:00</updated><author><name>Mathieu Leplatre</name></author><id>http://blog.mathieu-leplatre.info/git-annuler-proprement-un-commit-apres-un-push-fr.html</id><summary type="html">&lt;div class="section" id="ce-qu-il-faut-eviter"&gt;
&lt;h2&gt;Ce qu'il faut éviter&lt;/h2&gt;
&lt;p&gt;Pour annuler des commits, il existe la commande &lt;tt class="docutils literal"&gt;git reset&lt;/tt&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;git reset --hard HEAD~1
HEAD is now at 444b1cf Rhoo
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Celle-ci est pertinente tant que les commits n'ont pas été poussés. Git vous retiendra au &lt;tt class="docutils literal"&gt;push&lt;/tt&gt; d'ailleurs :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;git push
To /tmp/repo
 ! &lt;span class="o"&gt;[&lt;/span&gt;rejected&lt;span class="o"&gt;]&lt;/span&gt;        master -&amp;gt; master &lt;span class="o"&gt;(&lt;/span&gt;non-fast-forward&lt;span class="o"&gt;)&lt;/span&gt;
error: failed to push some refs to &lt;span class="s1"&gt;&amp;#39;/tmp/repo&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;En effet, à partir du moment où un commit existe sur le serveur, il est potentiellement utilisé
par des collaborateurs (&lt;em&gt;mergé, à la base d'une branche, etc.&lt;/em&gt;). On pourrait faire le sale et forcer le push :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;git push -f
Total 0 &lt;span class="o"&gt;(&lt;/span&gt;delta 0&lt;span class="o"&gt;)&lt;/span&gt;, reused 0 &lt;span class="o"&gt;(&lt;/span&gt;delta 0&lt;span class="o"&gt;)&lt;/span&gt;
To /tmp/repo
 + b67c343...444b1cf master -&amp;gt; master &lt;span class="o"&gt;(&lt;/span&gt;forced update&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Mais il y a beaucoup mieux !&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="ce-qu-il-faut-faire"&gt;
&lt;h2&gt;Ce qu'il faut faire&lt;/h2&gt;
&lt;p&gt;Annuler un commit, c'est finalement appliquer l'inverse de son &lt;strong&gt;diff&lt;/strong&gt; !&lt;/p&gt;
&lt;p&gt;On peut rediriger le diff des commits à annuler vers la commande &lt;tt class="docutils literal"&gt;patch &lt;span class="pre"&gt;--reverse&lt;/span&gt;&lt;/tt&gt; :)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;git diff HEAD^ | patch --reverse
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Pour faire plus simple, il y a &lt;tt class="docutils literal"&gt;git revert&lt;/tt&gt; !&lt;/p&gt;
&lt;p&gt;Par exemple pour annuler les trois derniers commits :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;git revert HEAD~3
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Ou pour annuler un commit en particulier :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;git revert 444b1cff
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Il suffit alors de pousser proprement le commit obtenu sur le
serveur. Les éventuels collaborateurs qui avaient basé leur travail sur les commits
annulés devront gérer les conflits au moment venu...&lt;/p&gt;
&lt;/div&gt;
</summary><category term="git"></category><category term="tips"></category></entry><entry><title>Two major Unity design failures</title><link href="http://blog.mathieu-leplatre.info/two-major-unity-design-failures.html" rel="alternate"></link><updated>2011-10-15T00:00:00+02:00</updated><author><name>Mathieu Leplatre</name></author><id>http://blog.mathieu-leplatre.info/two-major-unity-design-failures.html</id><summary type="html">&lt;p&gt;A great advantage of global menus is the ease of pointing them with the mouse.&lt;/p&gt;
&lt;p&gt;According to &lt;a class="reference external" href="http://en.wikipedia.org/wiki/Fitts%27s_law"&gt;Fitts' law&lt;/a&gt;,
the time to point a target is function of its distance and size. By sticking
the menus on the top part of the screen, the vertical dimension vanishes, since
the user can just throw his mouse on top to reach them.&lt;/p&gt;
&lt;p&gt;Unfortunately, two major design problems in Unity prevents from completely
turning global menus to account.&lt;/p&gt;
&lt;div class="section" id="window-buttons-dead-edges"&gt;
&lt;h2&gt;Window buttons dead edges&lt;/h2&gt;
&lt;p&gt;The user can not throw his mouse to the top-left corner to reach the close button,
since the edges are not clickable.&lt;/p&gt;
&lt;img alt="images/unity-deadzone.png" src="images/unity-deadzone.png" /&gt;
&lt;p&gt;&lt;a class="reference external" href="https://bugs.launchpad.net/ubuntu/+source/unity/+bug/874980"&gt;A bug was registered on Launchpad&lt;/a&gt; a couple of minutes before I wrote this
post.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="menus-not-always-shown"&gt;
&lt;h2&gt;Menus not always shown&lt;/h2&gt;
&lt;img alt="images/unity-menu-hidden.gif" src="images/unity-menu-hidden.gif" /&gt;
&lt;p&gt;The problem is &lt;a class="reference external" href="https://bugs.launchpad.net/ubuntu/+source/unity/+bug/701294"&gt;being discussed on Launchpad&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In my opinion, the current implementation is a terrible design :&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Lack of &lt;em&gt;afordance&lt;/em&gt; : There is no obvious hint that a menu is available for the current application.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Fitt's law&lt;/em&gt; fail : The user can not throw his mouse to the desired menu since it becomes visible only when he reaches it.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Fortunately, I am gesture and keyboard user (&lt;a class="reference external" href="apt://easystroke"&gt;easystroke&lt;/a&gt;, &lt;tt class="docutils literal"&gt;Alt+F10&lt;/tt&gt;, &lt;tt class="docutils literal"&gt;Alt+F4&lt;/tt&gt;)&lt;/p&gt;
&lt;/div&gt;
</summary><category term="ubuntu"></category><category term="unity"></category><category term="fail"></category></entry><entry><title>Une démo squelettique de python Flask CouchDB</title><link href="http://blog.mathieu-leplatre.info/une-demo-squelettique-de-python-flask-couchdb-fr.html" rel="alternate"></link><updated>2011-10-11T11:30:00+02:00</updated><author><name>Mathieu Leplatre</name></author><id>http://blog.mathieu-leplatre.info/une-demo-squelettique-de-python-flask-couchdb-fr.html</id><summary type="html">&lt;p&gt;Avec &lt;tt class="docutils literal"&gt;Flask&lt;/tt&gt; et &lt;tt class="docutils literal"&gt;Couchdb&lt;/tt&gt; (e.g. &lt;a class="reference external" href="http://packages.python.org/Flask-CouchDB/"&gt;Flask-CouchDB&lt;/a&gt;),
on peut faire rapidement des trucs amusants, voire très utiles !&lt;/p&gt;
&lt;p&gt;Voici un &lt;strong&gt;squelette&lt;/strong&gt; d'application, fonctionnel, qui stocke et récupère des objets crées à partir de posts HTTP.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;simplejson&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;flask&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Flask&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;couchdb.design&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ViewDefinition&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;flaskext.couchdb&lt;/span&gt;


&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Flask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="sd"&gt;CouchDB permanent view&lt;/span&gt;
&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;docs_by_author&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ViewDefinition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;docs&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;byauthor&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                &lt;span class="s"&gt;&amp;#39;function(doc) { emit(doc.author, doc); }&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="sd"&gt;Retrieve docs&lt;/span&gt;
&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="nd"&gt;@app.route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/&amp;lt;author_id&amp;gt;/docs&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;docs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;author_id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;docs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;docs_by_author&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;couch&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="n"&gt;author_id&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="n"&gt;docs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;simplejson&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;docs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="sd"&gt;Add doc&lt;/span&gt;
&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="nd"&gt;@app.route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/&amp;lt;author_id&amp;gt;/add&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;methods&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;POST&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;add_doc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;author_id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c"&gt;# Build doc with posted values&lt;/span&gt;
        &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;author&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;author_id&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;form&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c"&gt;# Insert into database&lt;/span&gt;
        &lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;couch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="ne"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;simplejson&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;ok&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="sd"&gt;Flask main&lt;/span&gt;
&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;__main__&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;DEBUG&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;COUCHDB_SERVER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;http://localhost:5984/&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;COUCHDB_DATABASE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;docsdemo&amp;#39;&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;manager&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;flaskext&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;couchdb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CouchDBManager&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;manager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;manager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_viewdef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;docs_by_author&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c"&gt;# Install the view&lt;/span&gt;
    &lt;span class="n"&gt;manager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;0.0.0.0&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;J'ai déposé ce snippet sur &lt;a class="reference external" href="https://gist.github.com/1277655"&gt;Gist&lt;/a&gt; si besoin.&lt;/p&gt;
&lt;p&gt;On peut attaquer l'application avec &lt;tt class="docutils literal"&gt;curl&lt;/tt&gt; :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;curl -d &lt;span class="s2"&gt;&amp;quot;title=Globalia&amp;amp;year=2004&amp;quot;&lt;/span&gt; http://0.0.0.0:5000/jc.rufin/add
&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;ok&amp;quot;&lt;/span&gt;: &lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;curl -d &lt;span class="s2"&gt;&amp;quot;title=Red%20Brazil&amp;amp;contest=goncourt&amp;quot;&lt;/span&gt; http://0.0.0.0:5000/jc.rufin/add
&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;ok&amp;quot;&lt;/span&gt;: &lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;curl http://0.0.0.0:5000/jc.rufin/docs
&lt;span class="o"&gt;[{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;title&amp;quot;&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Globalia&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;, &lt;span class="s2"&gt;&amp;quot;year&amp;quot;&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;2004&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;, &lt;span class="s2"&gt;&amp;quot;author&amp;quot;&lt;/span&gt;: &lt;span class="s2"&gt;&amp;quot;jc.rufin&amp;quot;&lt;/span&gt;, &lt;span class="s2"&gt;&amp;quot;_rev&amp;quot;&lt;/span&gt;: &lt;span class="s2"&gt;&amp;quot;1-3195...fbc8&amp;quot;&lt;/span&gt;, &lt;span class="s2"&gt;&amp;quot;_id&amp;quot;&lt;/span&gt;: &lt;span class="s2"&gt;&amp;quot;dec81d...1733c&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;,
&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;title&amp;quot;&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Red Brazil&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;, &lt;span class="s2"&gt;&amp;quot;contest&amp;quot;&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;goncourt&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;, &lt;span class="s2"&gt;&amp;quot;author&amp;quot;&lt;/span&gt;: &lt;span class="s2"&gt;&amp;quot;jc.rufin&amp;quot;&lt;/span&gt;, &lt;span class="s2"&gt;&amp;quot;_rev&amp;quot;&lt;/span&gt;: &lt;span class="s2"&gt;&amp;quot;1-7b15...a9a2&amp;quot;&lt;/span&gt;, &lt;span class="s2"&gt;&amp;quot;_id&amp;quot;&lt;/span&gt;: &lt;span class="s2"&gt;&amp;quot;dec81dc...17c0c&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;}]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;N'oubliez pas de colorier les cases à votre guise, sinon ce squelette ne sert à rien, le JSON étant déjà la langue maternelle de CouchDB.&lt;/p&gt;
</summary><category term="python"></category><category term="couchdb"></category><category term="flask"></category></entry><entry><title>Mes premiers pas avec Heroku</title><link href="http://blog.mathieu-leplatre.info/mes-premiers-pas-avec-heroku-fr.html" rel="alternate"></link><updated>2011-10-10T10:30:00+02:00</updated><author><name>Mathieu Leplatre</name></author><id>http://blog.mathieu-leplatre.info/mes-premiers-pas-avec-heroku-fr.html</id><summary type="html">&lt;p&gt;J'ai pris le temps de tester la plateforme &lt;a class="reference external" href="http://www.heroku.com"&gt;Heroku&lt;/a&gt;, qui fait pas mal de bruit
en ce moment.&lt;/p&gt;
&lt;p&gt;L'idée est simple : le développeur pousse son code dans une branche Git
pour déployer son application. Ils se chargent du reste.&lt;/p&gt;
&lt;p&gt;La &lt;a class="reference external" href="http://devcenter.heroku.com/articles/python"&gt;documentation pour déployer du python&lt;/a&gt; est bien faite.&lt;/p&gt;
&lt;div class="section" id="heroku-et-virtualenv"&gt;
&lt;h2&gt;heroku et virtualenv&lt;/h2&gt;
&lt;p&gt;Pour commencer, j'ai installé l'outil &lt;tt class="docutils literal"&gt;heroku&lt;/tt&gt; en ruby (sic), dans un &lt;em&gt;virtualenv&lt;/em&gt;&lt;/p&gt;
&lt;pre class="literal-block"&gt;
sudo aptitude install rubygems

virtualenv --no-site-packages env
source env/bin/activate
&lt;/pre&gt;
&lt;p&gt;Merci à Bruno, qui nous a expliqué récemment &lt;a class="reference external" href="http://bruno.im/2011/sep/29/streamline-your-django-workflow/"&gt;comment faire cohabiter les gems ruby et virtualenv&lt;/a&gt;&lt;/p&gt;
&lt;pre class="literal-block"&gt;
export GEM_HOME=&amp;quot;$VIRTUAL_ENV/gems&amp;quot;
export GEM_PATH=&amp;quot;&amp;quot;
export PATH=$PATH:$GEM_HOME/bin
&lt;/pre&gt;
&lt;p&gt;(À ajouter au hook dans &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;~/.virtualenvs/postactivate&lt;/span&gt;&lt;/tt&gt; pour plus tard)&lt;/p&gt;
&lt;p&gt;Pour terminer, il suffit de poser le &lt;em&gt;gem&lt;/em&gt;&lt;/p&gt;
&lt;pre class="literal-block"&gt;
gem install heroku
&lt;/pre&gt;
&lt;p&gt;Et j'ai bien &lt;tt class="docutils literal"&gt;heroku&lt;/tt&gt; cloisonné dans le &lt;em&gt;virtualenv&lt;/em&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="o"&gt;(&lt;/span&gt;env&lt;span class="o"&gt;)&lt;/span&gt;src&lt;span class="nv"&gt;$ &lt;/span&gt;which heroku
/home/mathieu/path/env/gems/bin/heroku

&lt;span class="o"&gt;(&lt;/span&gt;env&lt;span class="o"&gt;)&lt;/span&gt;src&lt;span class="nv"&gt;$ &lt;/span&gt;heroku &lt;span class="nb"&gt;help&lt;/span&gt;
Usage: heroku COMMAND &lt;span class="o"&gt;[&lt;/span&gt;--app APP&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;command&lt;/span&gt;-specific-options&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="heroku-et-la-configuration-de-l-application"&gt;
&lt;h2&gt;heroku et la Configuration de l'Application&lt;/h2&gt;
&lt;p&gt;Pour apprivoiser la plateforme, j'ai utilisé le &lt;em&gt;micro&lt;/em&gt;-framework &lt;a class="reference external" href="http://flask.pocoo.org/"&gt;Flask&lt;/a&gt;,
suggéré dans le tutorial python. C'est ultra-simple, ultra-léger, ultra-tout.&lt;/p&gt;
&lt;p&gt;Afin de gérer ma configuration, j'ai créé une classe &lt;tt class="docutils literal"&gt;Settings&lt;/tt&gt; qui utilise les variables d'environment:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c"&gt;# settings.py&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Settings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;DEBUG&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;DEBUG&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;TESTING&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;TESTING&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;PORT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;PORT&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;HOST&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;HOST&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;0.0.0.0&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Que je branche dans l'application :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c"&gt;# app.py&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;flask&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Flask&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;settings&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Settings&lt;/span&gt;


&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Flask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;settings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Settings&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c"&gt;#...&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;__main__&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c"&gt;# ...&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Ensuite grâce au client &lt;tt class="docutils literal"&gt;heroku&lt;/tt&gt;, je peux contrôler à distance
la configuration de mon application, qui est redémarrée à chaque changement :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="o"&gt;(&lt;/span&gt;env&lt;span class="o"&gt;)&lt;/span&gt;src&lt;span class="nv"&gt;$ &lt;/span&gt;heroku config
&lt;span class="nv"&gt;PATH&lt;/span&gt;              &lt;span class="o"&gt;=&lt;/span&gt;&amp;gt; bin:/usr/local/bin:/usr/bin:/bin
&lt;span class="nv"&gt;PYTHONUNBUFFERED&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt;&amp;gt; &lt;span class="nb"&gt;true&lt;/span&gt;

&lt;span class="o"&gt;(&lt;/span&gt;env&lt;span class="o"&gt;)&lt;/span&gt;src&lt;span class="nv"&gt;$ &lt;/span&gt;heroku config:add &lt;span class="nv"&gt;DEBUG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;True
Adding config vars:
  &lt;span class="nv"&gt;DEBUG&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&amp;gt; True
Restarting app... &lt;span class="k"&gt;done&lt;/span&gt;, v19.

&lt;span class="o"&gt;(&lt;/span&gt;env&lt;span class="o"&gt;)&lt;/span&gt;src&lt;span class="nv"&gt;$ &lt;/span&gt;heroku config
&lt;span class="nv"&gt;DEBUG&lt;/span&gt;             &lt;span class="o"&gt;=&lt;/span&gt;&amp;gt; True
&lt;span class="nv"&gt;PATH&lt;/span&gt;              &lt;span class="o"&gt;=&lt;/span&gt;&amp;gt; bin:/usr/local/bin:/usr/bin:/bin
&lt;span class="nv"&gt;PYTHONUNBUFFERED&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt;&amp;gt; &lt;span class="nb"&gt;true&lt;/span&gt;

&lt;span class="o"&gt;(&lt;/span&gt;env&lt;span class="o"&gt;)&lt;/span&gt;src&lt;span class="nv"&gt;$ &lt;/span&gt;heroku config:remove DEBUG
Removing DEBUG and restarting app... &lt;span class="k"&gt;done&lt;/span&gt;, v20.
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Je peux revenir en arrière quand un changement de config a posé problème :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="o"&gt;(&lt;/span&gt;env&lt;span class="o"&gt;)&lt;/span&gt;src&lt;span class="nv"&gt;$ &lt;/span&gt;heroku releases
Rel   Change                          By                    When
----  ----------------------          ----------            ----------
v20   Config remove DEBUG             your@mail.com         25 seconds ago
v19   Config add DEBUG                your@mail.com         1 minute ago


&lt;span class="o"&gt;(&lt;/span&gt;env&lt;span class="o"&gt;)&lt;/span&gt;src&lt;span class="nv"&gt;$ &lt;/span&gt;heroku rollback v19
Rolled back to v19
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
</summary><category term="python"></category><category term="flask"></category><category term="tips"></category><category term="heroku"></category></entry><entry><title>Avec Git rebase, vos arbres poussent droit</title><link href="http://blog.mathieu-leplatre.info/avec-git-rebase-vos-arbres-poussent-droit-fr.html" rel="alternate"></link><updated>2011-09-16T17:37:00+02:00</updated><author><name>Mathieu Leplatre</name></author><id>http://blog.mathieu-leplatre.info/avec-git-rebase-vos-arbres-poussent-droit-fr.html</id><summary type="html">&lt;div class="section" id="le-probleme"&gt;
&lt;h2&gt;Le problème&lt;/h2&gt;
&lt;p&gt;Par défaut, un &lt;tt class="docutils literal"&gt;git pull&lt;/tt&gt; est équivalent à &lt;tt class="docutils literal"&gt;git fetch&lt;/tt&gt; et &lt;tt class="docutils literal"&gt;git merge&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;Les &lt;tt class="docutils literal"&gt;merge&lt;/tt&gt;, c'est bien pour les branches, mais pour le tronc, c'est pénible : ça pollue l'historique et
ça zig-zag sévère !&lt;/p&gt;
&lt;img alt="images/git-merge-mess.png" class="align-center" src="images/git-merge-mess.png" /&gt;
&lt;/div&gt;
&lt;div class="section" id="la-solution"&gt;
&lt;h2&gt;La solution&lt;/h2&gt;
&lt;p&gt;En réalité, quand on travaille sur le tronc, ce qu'on veut c'est faire &lt;tt class="docutils literal"&gt;git fetch&lt;/tt&gt; et &lt;tt class="docutils literal"&gt;git rebase&lt;/tt&gt;.
C'est à dire, au lieu de ça :&lt;/p&gt;
&lt;pre class="literal-block"&gt;
      A-----B-----C master
     /             \
D---E---F---G---H---I origin/master
&lt;/pre&gt;
&lt;p&gt;on veut ça :&lt;/p&gt;
&lt;pre class="literal-block"&gt;
                  A---B---C master
                 /
D---E---F---G---H origin/master
&lt;/pre&gt;
&lt;p&gt;Autrement dit, un &lt;tt class="docutils literal"&gt;git pull &lt;span class="pre"&gt;--rebase&lt;/span&gt;&lt;/tt&gt; ! Pour le faire par défaut :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;git config --global branch.autosetuprebase always
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Et ensuite, au cas-où, pour le désactiver ponctuellement, utiliser &lt;tt class="docutils literal"&gt;git pull &lt;span class="pre"&gt;--no-rebase&lt;/span&gt;&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;Maintenant, le tronc, il est tout propre !&lt;/p&gt;
&lt;img alt="images/git-merge-clean.png" class="align-center" src="images/git-merge-clean.png" /&gt;
&lt;/div&gt;
&lt;div class="section" id="les-consequences"&gt;
&lt;h2&gt;Les conséquences ?&lt;/h2&gt;
&lt;p&gt;Lors d'un &lt;tt class="docutils literal"&gt;git pull&lt;/tt&gt;, il faudra résoudre chaque &lt;em&gt;commit&lt;/em&gt; conflictuel indépendamment (perso, je préfère).&lt;/p&gt;
&lt;p&gt;Les êtres humains voudront utiliser &lt;a class="reference external" href="http://meld.sourceforge.net/"&gt;meld&lt;/a&gt;. Il suffit de l'installer, et lors
d'un conflit, de lancer &lt;tt class="docutils literal"&gt;git mergetool&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;Une fois que tous les conflits sont résolus, terminer l'opération, avec &lt;tt class="docutils literal"&gt;git rebase &lt;span class="pre"&gt;--continue&lt;/span&gt;&lt;/tt&gt;, et pousser vos prouesses à
vos amis avec &lt;tt class="docutils literal"&gt;git push&lt;/tt&gt;.&lt;/p&gt;
&lt;/div&gt;
</summary><category term="git"></category><category term="tips"></category></entry><entry><title>A Virtual Local Server Room for you Developper</title><link href="http://blog.mathieu-leplatre.info/a-virtual-local-server-room-for-you-developper.html" rel="alternate"></link><updated>2011-09-02T09:12:00+02:00</updated><author><name>Mathieu Leplatre (credits: Anthony Prades)</name></author><id>http://blog.mathieu-leplatre.info/a-virtual-local-server-room-for-you-developper.html</id><summary type="html">&lt;p&gt;This how-to will help you setting-up a very powerful development environment
on your workstation, using virtual machines all in a virtual local network.&lt;/p&gt;
&lt;div class="section" id="but-why"&gt;
&lt;h2&gt;But Why ?&lt;/h2&gt;
&lt;p&gt;You work on various projects, with specific requirements, with various
technologies, diverse operating systems or cpu architectures, usually with
a couple of services like databases or Web servers.&lt;/p&gt;
&lt;p&gt;You would prefer not taking this whole family with you each time you start your machine.&lt;/p&gt;
&lt;p&gt;Probably, you also want to upgrade your workstation to the last unstable eye-candy OS
without compromising your projects dependencies and without reinstalling all this stuff,
or you may want to restore the environment you had when you were working on this famous project a year ago.&lt;/p&gt;
&lt;p&gt;You want your colleague to give you a hand, and would like to give him your
whole project environment and dependencies quickly and effortlessly ?
Your sysadmin put KVM on servers and you would like to push your local instances on
production in a blink ?&lt;/p&gt;
&lt;p&gt;The magic medicine exists, and is freely available :)&lt;/p&gt;
&lt;p&gt;At the end, you are promised to enjoy :&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;a GUI to manage your Virtual Machines (VM)&lt;/li&gt;
&lt;li&gt;a local domain to access your VMs by their name&lt;/li&gt;
&lt;li&gt;a fully integrated set of machines, accessible from each others&lt;/li&gt;
&lt;li&gt;movable and shareable virtual machines with automatic network configuration&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We chose the Linux Kernel-based Virtualization System (KVM), since it is maintained
along with the Linux kernel, and is thus fully integrated in the OS. However, this
how-to is mainly networking oriented and would be useful for any virtualization system.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="a-strict-minimum"&gt;
&lt;h2&gt;A Strict Minimum&lt;/h2&gt;
&lt;p&gt;A strict minimum is to install &lt;tt class="docutils literal"&gt;kvm&lt;/tt&gt; and a set of commands to control it : &lt;tt class="docutils literal"&gt;libvirt&lt;/tt&gt;.
As a human being, you may want a GUI : &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;virt-manager&lt;/span&gt;&lt;/tt&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;sudo apt-get install kvm libvirt-bin virt-manager
&lt;/pre&gt;&lt;/div&gt;
&lt;div class="section" id="virtual-machines-network"&gt;
&lt;h3&gt;Virtual Machines Network&lt;/h3&gt;
&lt;p&gt;Make sure your VM networking is set to &lt;em&gt;NAT&lt;/em&gt;. This will allow
your VM to access your host network (LAN, Internet, etc.)&lt;/p&gt;
&lt;p&gt;During your VM operating system installation, or after login into it,
setup your VM network interface as automatic DHCP.&lt;/p&gt;
&lt;p&gt;By default KVM creates a virtual network (&lt;tt class="docutils literal"&gt;virnet&lt;/tt&gt;). Inspect its setup
using &lt;tt class="docutils literal"&gt;ifconfig&lt;/tt&gt; or &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;virt-manager&lt;/span&gt;&lt;/tt&gt; in &lt;em&gt;Connection Details&lt;/em&gt; &amp;gt; &lt;em&gt;Virtual Networks&lt;/em&gt;.
Your VM and your host are thus accessible within this virtual network (probably &lt;tt class="docutils literal"&gt;172.16.23.0&lt;/tt&gt;).&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="a-local-network-domain"&gt;
&lt;h2&gt;A Local Network Domain&lt;/h2&gt;
&lt;p&gt;In order to access your VM by their name, we run a DNS daemon on main host. We chose &lt;em&gt;bind&lt;/em&gt; :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;sudo aptitude install bind9
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Add a new master zone, for example &lt;tt class="docutils literal"&gt;sillywalk.loc&lt;/tt&gt; in the file &lt;tt class="docutils literal"&gt;/etc/bind/named.conf.local&lt;/tt&gt; :&lt;/p&gt;
&lt;pre class="literal-block"&gt;
zone &amp;quot;sillywalk.loc&amp;quot; {
    type master;
    file &amp;quot;/etc/bind/db.sillywalk.loc&amp;quot;;
};
&lt;/pre&gt;
&lt;p&gt;Define your DNS entries :&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Set the name server authority (&lt;em&gt;SOA&lt;/em&gt;) to &lt;tt class="docutils literal"&gt;ns.sillywalk.loc&lt;/tt&gt; (&lt;em&gt;nameserver&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;Define a serial number like date+number (&lt;tt class="docutils literal"&gt;YYYYmmdd##&lt;/tt&gt;)&lt;/li&gt;
&lt;li&gt;Associate &lt;tt class="docutils literal"&gt;ns.sillywalk.loc&lt;/tt&gt; to the IP of your KVM virtual network (&lt;em&gt;see above paragraph&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;Define an alias &lt;cite&gt;gw.sillywalk.loc&lt;/cite&gt; so that you can refer to your host as &lt;cite&gt;gw&lt;/cite&gt; (&lt;em&gt;gateway&lt;/em&gt;) instead of &lt;cite&gt;ns&lt;/cite&gt;.&lt;/li&gt;
&lt;li&gt;Define a couple of entries for your VM (e.g. &lt;tt class="docutils literal"&gt;myvm1&lt;/tt&gt;, &lt;tt class="docutils literal"&gt;myvm2&lt;/tt&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For &lt;em&gt;bind&lt;/em&gt;, it would look like this &lt;em&gt;(started from an existing file like ``/etc/bind/db.empty``)&lt;/em&gt; :&lt;/p&gt;
&lt;pre class="literal-block"&gt;
;/etc/bind/db.sillywalk.loc
;
; BIND data file for local loopback interface
;
$TTL    604800
&amp;#64;   IN  SOA ns.sillywalk.loc. root.ns.sillywalk.loc. (
         2011080301     ; Serial
             604800     ; Refresh
              86400     ; Retry
            2419200     ; Expire
             604800 )   ; Negative Cache TTL
;
&amp;#64;   IN  NS      ns.sillywalk.loc.
&amp;#64;   IN  A       172.16.23.1
ns  IN  A       172.16.23.1
gw  IN  CNAME   ns.sillywalk.loc.

myvm1       IN  A   172.16.23.11
myvm2       IN  A   172.16.23.12
&lt;/pre&gt;
&lt;div class="section" id="use-your-dns"&gt;
&lt;h3&gt;Use your DNS&lt;/h3&gt;
&lt;p&gt;Use your Network Manager to set the search domain to &lt;tt class="docutils literal"&gt;sillywalk.loc&lt;/tt&gt; and
to add your local DNS server (&lt;tt class="docutils literal"&gt;127.0.0.1&lt;/tt&gt;) in front of the other(s).&lt;/p&gt;
&lt;p&gt;Apply and your &lt;tt class="docutils literal"&gt;/etc/resolv.conf&lt;/tt&gt; could then look like this :&lt;/p&gt;
&lt;pre class="literal-block"&gt;
# Generated by NetworkManager
search sillywalk.loc          # search domain
nameserver 127.0.0.1          # your local DNS server
nameserver 192.168.1.254      # your FAI/company DNS
nameserver 8.8.8.8            # Google public DNS
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="test-it"&gt;
&lt;h3&gt;Test it !&lt;/h3&gt;
&lt;p&gt;Even if your VM are not running, you can at least test the name resolving
and the default search domain :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;~&lt;span class="nv"&gt;$ &lt;/span&gt;ping myvm1.sillywalk.loc
PING myvm1.sillywalk.loc &lt;span class="o"&gt;(&lt;/span&gt;172.16.23.11&lt;span class="o"&gt;)&lt;/span&gt; 56&lt;span class="o"&gt;(&lt;/span&gt;84&lt;span class="o"&gt;)&lt;/span&gt; bytes of data.
&lt;span class="c"&gt;# (Ctrl+C)&lt;/span&gt;

~&lt;span class="nv"&gt;$ &lt;/span&gt;ping myvm2
PING myvm2.sillywalk.loc &lt;span class="o"&gt;(&lt;/span&gt;172.16.23.12&lt;span class="o"&gt;)&lt;/span&gt; 56&lt;span class="o"&gt;(&lt;/span&gt;84&lt;span class="o"&gt;)&lt;/span&gt; bytes of data.
&lt;span class="c"&gt;# (Ctrl+C)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="dynamic-configuration"&gt;
&lt;h2&gt;Dynamic Configuration&lt;/h2&gt;
&lt;p&gt;In order to make sure your VM always obtains the same IP adress when it
boots, we setup a DHCP daemon on host.&lt;/p&gt;
&lt;p&gt;We chose &lt;em&gt;ISC DHCP server&lt;/em&gt; :&lt;/p&gt;
&lt;pre class="literal-block"&gt;
sudo aptitude install isc-dhcp-server
&lt;/pre&gt;
&lt;p&gt;In the configuration file &lt;tt class="docutils literal"&gt;/etc/dhcp/dhcpd.conf&lt;/tt&gt;, we specify :&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;a domain name (&lt;tt class="docutils literal"&gt;sillywalk.loc&lt;/tt&gt;)&lt;/li&gt;
&lt;li&gt;the name server to be configured on clients (&lt;tt class="docutils literal"&gt;ns.sillywalk.loc&lt;/tt&gt;)&lt;/li&gt;
&lt;li&gt;the subnet and mask (&lt;em&gt;matching the KVM virtual network&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;an IP range (e.g. from &lt;tt class="docutils literal"&gt;172.16.23.10&lt;/tt&gt; to &lt;tt class="docutils literal"&gt;172.16.23.100&lt;/tt&gt;)&lt;/li&gt;
&lt;li&gt;the default gateway to be configured on clients (&lt;tt class="docutils literal"&gt;ns.sillywalk.loc&lt;/tt&gt;)&lt;/li&gt;
&lt;li&gt;... and two entries for &lt;tt class="docutils literal"&gt;myvm1&lt;/tt&gt; and  &lt;tt class="docutils literal"&gt;myvm2&lt;/tt&gt; with their Mac addresses.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="literal-block"&gt;
# /etc/dhcp/dhcpd.conf

option domain-name &amp;quot;sillywalk.loc&amp;quot;;
option domain-name-servers ns.sillywalk.loc;

subnet 172.16.23.0 netmask 255.255.255.0 {
  range 172.16.23.10 172.16.23.100;
  option broadcast-address 172.16.23.255;
  option routers gw.sillywalk.loc;
}

# Entries

host myvm1 {
  hardware ethernet 52:54:00:55:d1:80;
  fixed-address myvm1.sillywalk.loc;
}

host myvm2 {
  hardware ethernet 52:54:00:55:e1:66;
  fixed-address myvm2.sillywalk.loc;
}
&lt;/pre&gt;
&lt;div class="section" id="id1"&gt;
&lt;h3&gt;Test it !&lt;/h3&gt;
&lt;p&gt;Log you in on the VM.&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Configure its hostname (e.g. &lt;tt class="docutils literal"&gt;myvm1&lt;/tt&gt;, &lt;tt class="docutils literal"&gt;myvm2&lt;/tt&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;root@myvm1:~# cat /etc/hostname
myvm1
root@myvm1:~# cat /etc/hosts
127.0.0.1   localhost
127.0.1.1   myvm1.sillywalk.loc myvm1
&lt;/pre&gt;&lt;/div&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Make sure your VM network is set to DHCP automatic configuration&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;root@myvm1:~# cat /etc/network/interfaces
...
&lt;span class="c"&gt;# The primary network interface&lt;/span&gt;
allow-hotplug eth0
iface eth0 inet dhcp
&lt;/pre&gt;&lt;/div&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Reboot it (or restart networking)&lt;/li&gt;
&lt;li&gt;Check that it caught the right network configuration (IP, domain, and nameserver)&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;root@myvm1:~# ifconfig
eth0      Link encap:Ethernet  HWaddr 52:54:00:55:d1:80
          inet addr:172.16.23.11  Bcast:172.16.23.255  Mask:255.255.255.0
          ...
&lt;/pre&gt;&lt;/div&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;root@myvm1:~# cat /etc/resolv.conf
domain sillywalk.loc
search sillywalk.loc
nameserver 172.16.23.1
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="note"&gt;
&lt;h3&gt;Note&lt;/h3&gt;
&lt;p&gt;While your host is booting, the DHCP daemon usually starts before the KVM service, failing
then at accessing the virtual network interface (&lt;tt class="docutils literal"&gt;virbr1&lt;/tt&gt;, &lt;tt class="docutils literal"&gt;172.16.23.0&lt;/tt&gt;), not yet mounted.&lt;/p&gt;
&lt;p&gt;A simple solution is to manually restart your DHCP daemon, once your machine's booted :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;sudo /etc/init.d/isc-dhcp-server restart
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="checklist-to-add-a-new-vm"&gt;
&lt;h2&gt;Checklist to add a new VM&lt;/h2&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Get its Mac address (with &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;virt-manager&lt;/span&gt;&lt;/tt&gt; : &lt;em&gt;Virtual machine details&lt;/em&gt; &amp;gt; &lt;em&gt;Virtual network interface&lt;/em&gt; &amp;gt; &lt;em&gt;Mac Address&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;Add it to your DHCP configuration (&lt;tt class="docutils literal"&gt;/etc/dhcp/dhcpd.conf&lt;/tt&gt;)&lt;/li&gt;
&lt;li&gt;Add an IP for this entry in your DNS zone (&lt;tt class="docutils literal"&gt;/etc/bind/db.sillywalk.loc&lt;/tt&gt;) and increment the serial.&lt;/li&gt;
&lt;li&gt;Restart DHCP service and reload DNS configuration&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;sudo /etc/init.d/isc-dhcp-server restart
sudo /etc/init.d/bind9 reload
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you do that all day, you'll quickly find it relevant to write a script...&lt;/p&gt;
&lt;div class="section" id="note-on-cloning"&gt;
&lt;h3&gt;Note on cloning&lt;/h3&gt;
&lt;p&gt;Cloning your VM with &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;virt-manager&lt;/span&gt;&lt;/tt&gt; is a piece-of-cake.&lt;/p&gt;
&lt;p&gt;However, during cloning, KVM assigns a new Mac address to the clone.
For debian-based virtual machines (+Ubuntu), log you in on the clone, and reinitialize network interfaces names :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;sudo rm /etc/udev/rules.d/70-persistent-net.rules
sudo reboot
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="conclusion"&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Your virtual machines can :&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;access your network (LAN, Internet) and your host (at &lt;tt class="docutils literal"&gt;ns.sillywalk.loc&lt;/tt&gt;)&lt;/li&gt;
&lt;li&gt;be accessed at &lt;tt class="docutils literal"&gt;user&amp;#64;hostname&lt;/tt&gt; (from host or from other VMs)&lt;/li&gt;
&lt;li&gt;be moved to any host set up likewise (since VM networking is fully automatic)&lt;/li&gt;
&lt;li&gt;be cloned easily&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Read again &amp;quot;&lt;a class="reference internal" href="#but-why"&gt;But Why ?&lt;/a&gt;&amp;quot; and enjoy your new life !&lt;/p&gt;
&lt;/div&gt;
</summary><category term="network"></category><category term="kvm"></category><category term="virtualization"></category><category term="howto"></category></entry><entry><title>A very Simple and Stupid plugin system in python</title><link href="http://blog.mathieu-leplatre.info/a-very-simple-and-stupid-plugin-system-in-python.html" rel="alternate"></link><updated>2011-09-02T00:00:00+02:00</updated><author><name>Mathieu Leplatre</name></author><id>http://blog.mathieu-leplatre.info/a-very-simple-and-stupid-plugin-system-in-python.html</id><summary type="html">&lt;p&gt;Two convenience functions for listing and importing python modules :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c"&gt;# utils.py&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;plugins_list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;plugins_dirs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot; List all python modules in specified plugins folders &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;plugins_dirs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pathsep&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;filename&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;listdir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;splitext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ext&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;endswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;.py&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;import_plugins&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;plugins_dirs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot; Import modules into specified environment (symbol table) &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;plugins_list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;plugins_dirs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;__import__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And now use &lt;tt class="docutils literal"&gt;import_plugins()&lt;/tt&gt; wherever you need to use them !&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c"&gt;# yourapp.py&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;utils&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;import_plugins&lt;/span&gt;

&lt;span class="n"&gt;plugins_dirs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;plugins/:module/plugins/&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;plugins_dirs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pathsep&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="n"&gt;import_plugins&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;plugins_dirs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;globals&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Note that in order to list all sub-classes of a specific one, you can use &lt;a class="reference external" href="http://code.activestate.com/recipes/576949/"&gt;this
recursive function&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;That's all folks !&lt;/p&gt;
&lt;p&gt;It is very simple and very stupid, but useful :) You might now want to have
a look at serious stuff like &lt;a class="reference external" href="http://packages.python.org/Yapsy/"&gt;Yapsy&lt;/a&gt; or
&lt;a class="reference external" href="http://packages.python.org/distribute/pkg_resources.html"&gt;PkgResouces&lt;/a&gt;.&lt;/p&gt;
</summary><category term="python"></category></entry><entry><title>Le piège des QThread</title><link href="http://blog.mathieu-leplatre.info/le-piege-des-qthread-fr.html" rel="alternate"></link><updated>2011-09-01T11:09:00+02:00</updated><author><name>Mathieu Leplatre</name></author><id>http://blog.mathieu-leplatre.info/le-piege-des-qthread-fr.html</id><summary type="html">&lt;p&gt;&lt;em&gt;Article original publié chez&lt;/em&gt; &lt;a class="reference external" href="http://www.makina-corpus.org/blog/le-pi%C3%A8ge-des-qthread"&gt;Makina Corpus&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Il y a de nombreux billets de blogs, posts sur des forums, tutoriaux,
pages Wiki et autres, mais au final, à part le fameux &lt;a class="reference external" href="http://labs.qt.nokia.com/2010/06/17/youre-doing-it-wrong/"&gt;&amp;quot;You're doing it wrong&amp;quot;&lt;/a&gt;,
qui peut paraître obscure au premier abord, je n'ai pas trouvé de résumé
de l'attrape-nigaud que je vais illustrer ici.&lt;/p&gt;
&lt;div class="section" id="le-piege"&gt;
&lt;h2&gt;Le piège&lt;/h2&gt;
&lt;p&gt;Naturellement, quand on veut faire une thread, on a envie d'hériter de l'objet
&lt;a class="reference external" href="http://doc.qt.nokia.com/latest/qthread.html"&gt;QThread&lt;/a&gt;. C'est ce qu'on fait avec le module &lt;tt class="docutils literal"&gt;threading&lt;/tt&gt; de python (en Java aussi il me semble).&lt;/p&gt;
&lt;p&gt;Voici ce qu'on écrit naturellement : &lt;tt class="docutils literal"&gt;Objet&lt;/tt&gt;, la classe qui file l'ordre et &lt;tt class="docutils literal"&gt;Worker&lt;/tt&gt;, une classe qui bosse dur en arrière plan. On connecte les signaux et on démarre !&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;sys&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;PyQt4.QtCore&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;PyQt4.QtGui&lt;/span&gt;  &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;QApplication&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;QObject&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;emitSignal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SIGNAL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;aSignal()&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Worker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;QThread&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;aSlot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Slot is executed in thread : &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;currentThreadId&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;__main__&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;QApplication&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Main application thread is : &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;currentThreadId&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;worker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Worker&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;QObject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SIGNAL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;aSignal()&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;worker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;aSlot&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;worker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;emitSignal&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Done.&amp;quot;&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exec_&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Ici, comme le slot &lt;tt class="docutils literal"&gt;aSlot()&lt;/tt&gt; est défini dans la classe &lt;tt class="docutils literal"&gt;Worker&lt;/tt&gt;, qui hérite de &lt;tt class="docutils literal"&gt;QThread&lt;/tt&gt;, on
pense naturellement qu'il va être exécuté en arrière-plan. Que nenni!&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;Main application thread is :  140068661352224
&lt;span class="c"&gt;# (... wait 1 sec ...)&lt;/span&gt;
Slot is executed in thread :  140068661352224
Done.
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="la-solution"&gt;
&lt;h2&gt;La solution&lt;/h2&gt;
&lt;p&gt;Un secret ? Les &lt;tt class="docutils literal"&gt;QThread&lt;/tt&gt; ne sont pas des threads. Elles enrobent l'execution d'une thread.&lt;/p&gt;
&lt;p&gt;L'appartenance (affinité) d'un objet à une thread détermine le &lt;a class="reference external" href="http://doc.qt.nokia.com/latest/qt.html#ConnectionType-enum"&gt;type de connexion&lt;/a&gt; &lt;a class="reference external" href="http://doc.qt.nokia.com/latest/threads-qobject.html#signals-and-slots-across-threads"&gt;utilisé par défaut&lt;/a&gt;, et par conséquent le comportement lors de l'execution des slots.&lt;/p&gt;
&lt;p&gt;Ce qu'il faut écrire : &lt;tt class="docutils literal"&gt;Worker&lt;/tt&gt; n'est plus une &lt;tt class="docutils literal"&gt;QThread&lt;/tt&gt;, on force son affinité dans une thread avec &lt;tt class="docutils literal"&gt;moveToThread()&lt;/tt&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;QObject&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;emitSignal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SIGNAL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;aSignal()&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Worker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;QObject&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;aSlot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Slot is executed in thread : &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;currentThreadId&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;__main__&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;QApplication&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Main application thread is : &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;currentThreadId&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;worker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Worker&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;thread&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;QThread&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;worker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;moveToThread&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;QObject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SIGNAL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;aSignal()&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;worker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;aSlot&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;emitSignal&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Done.&amp;quot;&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exec_&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Désormais, l'exécution est bien asynchrone, comme on le souhaitait.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;Main application thread is :  139961882056480
Done.
&lt;span class="c"&gt;# (... wait 1 sec ...)&lt;/span&gt;
Slot is executed in thread :  139961512900352
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Tout simplement ! Si j'avais lu mon article avant, je n'aurais pas perdu autant de temps à lire toutes ces docs ambiguës sur le Net.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Sources&lt;/strong&gt;:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://developer.qt.nokia.com/wiki/Threads_Events_QObjects"&gt;Explications complètes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://doc.qt.nokia.com/4.7-snapshot/thread-basics.html"&gt;Thread Basics&lt;/a&gt; &lt;em&gt;(attention au piège)&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
</summary><category term="qt"></category><category term="python"></category><category term="tips"></category></entry><entry><title>PostGIS data in C++ using GDAL and Qt</title><link href="http://blog.mathieu-leplatre.info/postgis-data-in-c-using-gdal-and-qt.html" rel="alternate"></link><updated>2011-08-23T10:25:00+02:00</updated><author><name>Mathieu Leplatre</name></author><id>http://blog.mathieu-leplatre.info/postgis-data-in-c-using-gdal-and-qt.html</id><summary type="html">&lt;p&gt;&lt;em&gt;Original post at&lt;/em&gt; &lt;a class="reference external" href="http://makina-corpus.org"&gt;Makina Corpus&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I did not find any ready-to-use snippets on the Web on this matter, so if
you are lucky enough, you'll find this one.&lt;/p&gt;
&lt;p&gt;The objective is to read GIS geometries from a PostGIS database and manipulate
them in C++. I use Qt here, but it is not really a prerequisite, it just
helps a lot. Well, actually, it saves lives.&lt;/p&gt;
&lt;div class="section" id="database-connection"&gt;
&lt;h2&gt;Database Connection&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;m_db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;QSqlDatabase&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;addDatabase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;QPSQL&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;m_db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setHostName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;host&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;m_db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setDatabaseName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;dbname&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;m_db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setUserName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;user&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;m_db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setPassword&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;pass&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Do not close the database at the end of each query.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;m_db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;m_db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;QSqlDatabase&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;  &lt;span class="c1"&gt;// reinitialize for real&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Shut it down like this in your class' destructor or you may have errors like
&lt;em&gt;QSqlDatabasePrivate::removeDatabase: connection 'qt_sql_default_connection' is still in use, all queries will cease to work&lt;/em&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="records-reading"&gt;
&lt;h2&gt;Records Reading&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;QSqlQueryModel&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;QSqlQueryModel&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;setQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;SELECT id, ST_AsBinary(the_geom) AS the_geom &amp;quot;&lt;/span&gt;
                &lt;span class="s"&gt;&amp;quot;FROM table&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;numRows&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;rowCount&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;numRows&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Read fields&lt;/span&gt;
    &lt;span class="n"&gt;qlonglong&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;id&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;toLongLong&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;QByteArray&lt;/span&gt; &lt;span class="n"&gt;wkb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;the_geom&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;toByteArray&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// Process !&lt;/span&gt;
    &lt;span class="n"&gt;processRecord&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;wkb&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;QByteArray uses &lt;a class="reference external" href="http://doc.qt.nokia.com/latest/implicit-sharing.html"&gt;implicit sharing&lt;/a&gt;
and can be passed as argument without being copied.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="geometries-parsing"&gt;
&lt;h2&gt;Geometries Parsing&lt;/h2&gt;
&lt;p&gt;In this part, we rely on &lt;a class="reference external" href="http://www.gdal.org"&gt;GDAL (Geospatial Data Abstraction Library)&lt;/a&gt;
&lt;a class="reference external" href="http://www.gdal.org/ogr/osr_tutorial.html"&gt;OGRSpatialReference&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It provides an API to access geometries coordinates etc.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="cp"&gt;#include &amp;quot;ogrsf_frmts.h&amp;quot; &lt;/span&gt;&lt;span class="c1"&gt;// GDAL&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;Class&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;processRecord&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qlonglong&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;QByteArray&lt;/span&gt; &lt;span class="n"&gt;wkb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;OGRSpatialReference&lt;/span&gt; &lt;span class="n"&gt;osr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;OGRGeometry&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;geom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Parse WKB&lt;/span&gt;
    &lt;span class="n"&gt;OGRErr&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;OGRGeometryFactory&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;createFromWkb&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;wkb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;constData&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;osr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;geom&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;OGRERR_NONE&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="c1"&gt;// process error, like emit signal&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Analyse geometry by type and process them as you wish&lt;/span&gt;
    &lt;span class="n"&gt;OGRwkbGeometryType&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;wkbFlatten&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;geom&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;getGeometryType&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nl"&gt;wkbLineString:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;OGRLineString&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;poRing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OGRLineString&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;geom&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

            &lt;span class="c1"&gt;// Access line string nodes for example :&lt;/span&gt;
            &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;numNode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;poRing&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;getNumPoints&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="n"&gt;OGRPoint&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;numNode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;poRing&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;getPoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;qDebug&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getX&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getY&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nl"&gt;wkbMultiLineString:&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;OGRGeometryCollection&lt;/span&gt;  &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;poCol&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OGRGeometryCollection&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;geom&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;numCol&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;poCol&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;getNumGeometries&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;numCol&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// Access line length for example :&lt;/span&gt;
                &lt;span class="n"&gt;qDebug&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;poCol&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;getGeometryRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;get_Length&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;// process error, like emit signal&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Clean-up&lt;/span&gt;
    &lt;span class="n"&gt;OGRGeometryFactory&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;destroyGeometry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;geom&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In this snippet, I only process linestrings, but all &lt;a class="reference external" href="http://www.gdal.org/ogr/ogr__core_8h.html#800236a0d460ef66e687b7b65610f12a"&gt;geometry types are available&lt;/a&gt;.
Consider writing a recursive function for geometry collections and so forth...&lt;/p&gt;
&lt;p&gt;Hope this helped !&lt;/p&gt;
&lt;/div&gt;
</summary><category term="c++"></category><category term="qt"></category><category term="postgis"></category><category term="gdal"></category></entry><entry><title>Django, gestion des settings d'application simplifiée</title><link href="http://blog.mathieu-leplatre.info/django-gestion-des-settings-dapplication-simplifiee-fr.html" rel="alternate"></link><updated>2011-07-29T18:30:00+02:00</updated><author><name>Mathieu Leplatre</name></author><id>http://blog.mathieu-leplatre.info/django-gestion-des-settings-dapplication-simplifiee-fr.html</id><summary type="html">&lt;p&gt;Je reprends ici la méthode présentée par &lt;a class="reference external" href="http://blog.akei.com/post/4575980188/une-autre-facon-de-gerer-ses-settings-dapplication"&gt;Nicolas&lt;/a&gt; et je la couple avec mon petit &lt;a class="reference external" href="https://github.com/makinacorpus/easydict"&gt;EasyDict&lt;/a&gt; pour alléger l'utilisation !
Comme ses snippets sont drôles, je ne les change pas !&lt;/p&gt;
&lt;div class="section" id="parametres-par-default-de-l-application"&gt;
&lt;h2&gt;Paramètres par défault de l'application&lt;/h2&gt;
&lt;p&gt;On a juste un constructeur à ajouter par rapport à ce qu'avait présenté NiKo (avec &lt;a class="reference external" href="http://pypi.python.org/pypi/easydict/"&gt;EasyDict installé&lt;/a&gt;).&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c"&gt;# apps/my_app/__init__.py&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.conf&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;easydict&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;EasyDict&lt;/span&gt;

&lt;span class="n"&gt;app_settings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;EasyDict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="s"&gt;&amp;#39;FOO&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;&amp;#39;ENABLE_CHUCK_NORRIZ_MODE&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="nb"&gt;getattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;MY_APP_CONFIG&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{})))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="surcharge-dans-le-projet"&gt;
&lt;h2&gt;Surcharge dans le projet&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c"&gt;# settings.py&lt;/span&gt;
&lt;span class="n"&gt;MY_APP_CONFIG&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;&amp;#39;ENABLE_CHUCK_NORRIZ_MODE&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="utilisation"&gt;
&lt;h2&gt;Utilisation !&lt;/h2&gt;
&lt;p&gt;EasyDict transforme les clés du &lt;cite&gt;dict&lt;/cite&gt; en attributs, on accède aux settings en toute simplicité !&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c"&gt;# foo/bar.py&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;my_app&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;app_settings&lt;/span&gt;

&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="n"&gt;app_settings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FOO&lt;/span&gt; &lt;span class="c"&gt;# 42&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c"&gt;# apps/my_app/utils.py&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;.&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;app_settings&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;app_settings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ENABLE_CHUCK_NORRIZ_MODE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;Chuck Norriz is watching you&amp;#39;&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;Dance dance, little lamb&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
</summary><category term="django"></category><category term="easydict"></category></entry><entry><title>Carte des vélos avec Leaflet</title><link href="http://blog.mathieu-leplatre.info/carte-des-velos-avec-leaflet-fr.html" rel="alternate"></link><updated>2011-05-30T15:25:00+02:00</updated><author><name>Mathieu Leplatre</name></author><id>http://blog.mathieu-leplatre.info/carte-des-velos-avec-leaflet-fr.html</id><summary type="html">&lt;p&gt;&lt;em&gt;Article original publié chez&lt;/em&gt; &lt;a class="reference external" href="http://makina-corpus.org"&gt;Makina Corpus&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Les bookmarks, un peu comme les cahiers de recettes, c'est bien de les remplir mais encore faut-il trouver les bons au moment adéquate !
Même quand il s'agit d'outils, de bibliothèques et de services Web, il faut trouver l'occasion de les tester avant le grand soir !
Et si on veut en faire un article de blog, alors là, il faut en plus donner envie d'y goûter :)&lt;/p&gt;
&lt;p&gt;Ici, je prends plein d'ingrédients trouvés au bord des chemins :&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://packages.python.org/pyquery/"&gt;pyquery&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://leaflet.cloudmade.com"&gt;leaflet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://developer.yahoo.com/yql/"&gt;Yahoo Query Language&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://mustache.github.com/"&gt;mustache&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Je secoue bien fort ! (sans oublier de saupoudrer de &lt;a class="reference external" href="http://jquery.com"&gt;jquery&lt;/a&gt;) et j'obtiens une carte interactive des stations vélos de Toulouse !&lt;/p&gt;
&lt;div class="section" id="la-liste-des-stations"&gt;
&lt;h2&gt;La liste des stations&lt;/h2&gt;
&lt;p&gt;Sur le site &lt;a class="reference external" href="http://velonow.info"&gt;http://velonow.info&lt;/a&gt;, je récupère un fichier XML qui contient
la liste statique des stations de vélo et leurs identifiants.&lt;/p&gt;
&lt;p&gt;C'est l'occasion d'utiliser &lt;a class="reference external" href="http://packages.python.org/pyquery/"&gt;pyquery&lt;/a&gt; pour le transformer en GeoJSON. &lt;a class="reference external" href="http://www.gawel.org"&gt;Gawel&lt;/a&gt; nous l'avait présenté aux djangocongs, il s'agit du portage de l'API de JQuery en python !&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;pyquery&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;PyQuery&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;pq&lt;/span&gt;

&lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;http://server.com/file.xml&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;pq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;marker&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
    &lt;span class="n"&gt;pt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;geojson&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Point&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;lng&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                        &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;lat&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)])&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Je trouve ça génial d'avoir la même syntaxe de manipulation du DOM en python et en javascript ! Et pour faire du webscrapping, c'est top !&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="affichage-de-la-carte"&gt;
&lt;h2&gt;Affichage de la carte&lt;/h2&gt;
&lt;p&gt;&lt;a class="reference external" href="http://cloudmade.com"&gt;Cloudmade&lt;/a&gt; a créé &lt;a class="reference external" href="http://leaflet.cloudmade.com"&gt;leaflet&lt;/a&gt; qui rejoint &lt;a class="reference external" href="http://www.tile5.org"&gt;Tile5&lt;/a&gt; et &lt;a class="reference external" href="http://polymaps.org"&gt;Polymaps&lt;/a&gt; en tant que challenger d'Openlayers !&lt;/p&gt;
&lt;p&gt;C'est une bibliothèque légère, jolie, fluide, optimisée pour les mobiles,
et même compatible Internet Explorer !&lt;/p&gt;
&lt;p&gt;Pour afficher une carte centrée sur la localisation du visiteur de la page, il suffit de faire ça :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;map&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;L&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;map&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;cloudmadeUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;http://{s}.tile.cloudmade.com/BC9A493B41014CAABB98F0471D759707/997/256/{z}/{x}/{y}.png&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;cloudmade&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;L&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TileLayer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cloudmadeUrl&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addLayer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cloudmade&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;locateAndSetView&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Pour l'instant, Leaflet ne gère pas les couches au format GeoJSON, en
attendant &lt;a class="reference external" href="https://github.com/CloudMade/Leaflet/issues/13"&gt;la prochaine release&lt;/a&gt;,
nous allons ajouter les points des stations en 2 coups de cuillère à pot :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getJSON&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;each&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;features&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;cc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;geometry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;coordinates&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;marker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;L&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Marker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;L&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;LatLng&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]));&lt;/span&gt;
        &lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addLayer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;marker&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="details-d-une-station-en-popup"&gt;
&lt;h2&gt;Détails d'une station en popup&lt;/h2&gt;
&lt;p&gt;Les détails d'une station (nombre de vélos, emplacements, libres, occupés) sont disponibles en fournissant un identifiant sur le site de &lt;a class="reference external" href="http://www.velo.toulouse.fr"&gt;velo toulouse&lt;/a&gt;.
Mais lorsqu'on appelle la page en Ajax, le corps de la réponse XML est vide. Une protection contre la bidouillabilité sûrement.&lt;/p&gt;
&lt;p&gt;C'est là que &lt;a class="reference external" href="http://developer.yahoo.com/yql/"&gt;Yahoo Query Language&lt;/a&gt; nous aide ! On passe par Yahoo pour accèder aux ressources du Web avec &lt;a class="reference external" href="http://developer.yahoo.com/yql/console/"&gt;des requêtes similaires aux bases de données&lt;/a&gt; !&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;yql&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;select * from xml where url = &amp;#39;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;#39;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="nx"&gt;yqlurl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;http://query.yahooapis.com/v1/public/yql?q=&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nb"&gt;encodeURIComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;yql&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;yqlurl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// show data in pop up !&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Je fais une petite fonction pour transformer l'XML récupéré en objet :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;xml2obj&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;xmldata&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
    &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;xmldata&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;each&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;nodeName&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&amp;lt;station&amp;gt;
    &amp;lt;free&amp;gt;12&amp;lt;/free&amp;gt;
    &amp;lt;available&amp;gt;4&amp;lt;/available&amp;gt;
    &amp;lt;total&amp;gt;16&amp;lt;/total&amp;gt;
&amp;lt;/station&amp;gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;devient :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;free&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;available&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Pour mettre en forme ces informations dans la pop-up, nous allons utiliser &lt;a class="reference external" href="http://mustache.github.com/"&gt;mustache&lt;/a&gt; !
Conceptuellement, il s'agit tout simplement d'un moteur de template avec &lt;a class="reference external" href="http://mustache.github.com/mustache.5.html"&gt;une syntaxe simplifiée&lt;/a&gt; ! Il y a une implémentation
dans quasiment tous les languages, dont Javascript.&lt;/p&gt;
&lt;p&gt;Cela évite principalement de faire du code javascript pour la mise en forme des données, notamment pour
celles récupérées en JSON via Ajax.&lt;/p&gt;
&lt;p&gt;On construit une chaîne avec les fameuses &lt;cite&gt;{{}}&lt;/cite&gt; et on fournit un objet pour substituer les valeurs :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;xml2obj&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;xmldata&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;station&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="nx"&gt;template&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;lt;h2&amp;gt;Station #{{ number }}&amp;lt;/h2&amp;gt;&lt;/span&gt;
&lt;span class="s2"&gt;                &amp;lt;p&amp;gt;{{ address }}&amp;lt;/p&amp;gt;                    \&lt;/span&gt;
&lt;span class="s2"&gt;                {{# station }}                          \&lt;/span&gt;
&lt;span class="s2"&gt;                &amp;lt;ul&amp;gt;                                    \&lt;/span&gt;
&lt;span class="s2"&gt;                  &amp;lt;li&amp;gt;{{ available }} available&amp;lt;/li&amp;gt;    \&lt;/span&gt;
&lt;span class="s2"&gt;                  &amp;lt;li&amp;gt;{{ free }} free slots&amp;lt;/li&amp;gt;        \&lt;/span&gt;
&lt;span class="s2"&gt;                &amp;lt;/ul&amp;gt;                                   \&lt;/span&gt;
&lt;span class="s2"&gt;                {{/ station }}&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Mustache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;to_html&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;template&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Show marker popup !&lt;/span&gt;
&lt;span class="nx"&gt;marker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bindPopup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;openPopup&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Et voilà !&lt;/p&gt;
&lt;img alt="images/leaflet-velo.png" src="images/leaflet-velo.png" /&gt;
&lt;/div&gt;
</summary><category term="javascript"></category><category term="leaflet"></category><category term="mustache"></category><category term="pyquery"></category><category term="jquery"></category></entry><entry><title>URL reverse en Javascript avec django</title><link href="http://blog.mathieu-leplatre.info/url-reverse-en-javascript-avec-django-fr.html" rel="alternate"></link><updated>2011-05-27T15:25:00+02:00</updated><author><name>Mathieu Leplatre</name></author><id>http://blog.mathieu-leplatre.info/url-reverse-en-javascript-avec-django-fr.html</id><summary type="html">&lt;p&gt;&lt;em&gt;Article original publié chez&lt;/em&gt; &lt;a class="reference external" href="http://makina-corpus.org"&gt;Makina Corpus&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Un aspect fondamental de la philosophie django consiste à éviter toute sorte de redondance : &lt;a class="reference external" href="https://docs.djangoproject.com/en/dev/misc/design-philosophies/"&gt;Don't Repeat Yourself&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;La tentation est souvent trop belle, et respecter les fondamentaux s'avère parfois difficile ! C'est le cas de la réécriture d'URL en Javascript.&lt;/p&gt;
&lt;p&gt;Imaginons l'URL suivante définie dans &lt;cite&gt;urls.py&lt;/cite&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;r&amp;#39;^/plop/(?P&amp;lt;x&amp;gt;\d)/(?P&amp;lt;y&amp;gt;\d)$&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;plopview&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;plop&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Pour utiliser cette URL en Javascript avec des paramètres variables, on peut imaginer plusieurs approches.&lt;/p&gt;
&lt;div class="section" id="j-aime-pas"&gt;
&lt;h2&gt;J'aime pas&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;generic&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;{% url &amp;#39;plop&amp;#39; 0 0 %}&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;generic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;0/0&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Pas DRY ! à cause des &lt;cite&gt;/&lt;/cite&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="s2"&gt;&amp;quot;{% url &amp;#39;plop&amp;#39; 0 0 %}&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;../../&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;/&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Pas DRY non plus !&lt;/p&gt;
&lt;p&gt;On peut aussi changer le pattern pour éviter les &lt;cite&gt;/&lt;/cite&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;r&amp;#39;^/plop/(?P&amp;lt;x&amp;gt;[\d]|x)/(?P&amp;lt;y&amp;gt;[\d]|y)$&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;plop&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;generic&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;{% url &amp;#39;toto&amp;#39; &amp;#39;x&amp;#39; &amp;#39;y&amp;#39; %}&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;generic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;x&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;y&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;C'est mieux, mais pas DRY ! à cause des &lt;cite&gt;x&lt;/cite&gt;, &lt;cite&gt;y&lt;/cite&gt;.&lt;/p&gt;
&lt;p&gt;On pourrait aussi imaginer une vue django qui ferait le &lt;cite&gt;reverse()&lt;/cite&gt;. Mais cela multiplierait les aller-retours serveur, ce qui n'est pas toujours recommandé...&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="la-bonne"&gt;
&lt;h2&gt;La bonne&lt;/h2&gt;
&lt;p&gt;Il existe une application pour ça ! &lt;a class="reference external" href="https://github.com/Dimitri-Gnidash/django-js-utils"&gt;django-js-utils&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Elle se charge de générer un fichier Javascript (&lt;cite&gt;settings.URLS_JS_GENERATED_FILE&lt;/cite&gt;) grâce à une commande de gestion&lt;/p&gt;
&lt;pre class="literal-block"&gt;
python manage.js js_urls
&lt;/pre&gt;
&lt;p&gt;Ensuite on utilise explicitement le fichier généré&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&amp;lt;script type=&amp;quot;text/javascript&amp;quot; src=&amp;quot;{{ MEDIA_URL }}/js/dutils.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script type=&amp;quot;text/javascript&amp;quot; src=&amp;quot;{{ MEDIA_URL }}/js/dutils.conf.urls.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Et on fait du vrai DRY !&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nx"&gt;dutils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;urls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;plop&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;x&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;y&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Gagné ! \o/&lt;/p&gt;
&lt;p&gt;Un inconvénient à noter tout de même : la liste de l'ensemble des URLs de l'application est accessible au public. Mais j'ai pas mieux ma pauvre dame !&lt;/p&gt;
&lt;/div&gt;
</summary><category term="django"></category><category term="javascript"></category></entry><entry><title>Django et Jenkins</title><link href="http://blog.mathieu-leplatre.info/django-et-jenkins-fr.html" rel="alternate"></link><updated>2011-04-28T17:25:00+02:00</updated><author><name>Mathieu Leplatre</name></author><id>http://blog.mathieu-leplatre.info/django-et-jenkins-fr.html</id><summary type="html">&lt;p&gt;&lt;em&gt;Article original publié chez&lt;/em&gt; &lt;a class="reference external" href="http://makina-corpus.org"&gt;Makina Corpus&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Lors des &lt;a class="reference external" href="http://rencontres.django-fr.org/2011/"&gt;Recontres Django 2011&lt;/a&gt;, &lt;a class="reference external" href="http://www.akei.com"&gt;Nicolas Perriault&lt;/a&gt; a présenté les principes de l'&lt;a class="reference external" href="http://fr.wikipedia.org/wiki/Int%C3%A9gration_continue"&gt;intégration continue&lt;/a&gt; avec &lt;a class="reference external" href="http://djangoproject.com"&gt;Django&lt;/a&gt; et &lt;a class="reference external" href="http://jenkins-ci.org/"&gt;Jenkins&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Le diaporama, &lt;a class="reference external" href="http://www.akei.com/presentations/2011-Djangocong/index.html"&gt;disponible en ligne&lt;/a&gt;, suffit amplement pour démarrer !&lt;/p&gt;
&lt;p&gt;Mais pour qu'un projet django soit testé facilement, il doit se déployer et se lancer facilement ! C'est certes l'occasion de peaufiner l'automatisation, mais c'est loin d'être trivial quand il y a du SIG, du &lt;a class="reference external" href="http://celeryproject.org"&gt;celery&lt;/a&gt; ...
Je vais tenter de partager mes notes dans ce billet.&lt;/p&gt;
&lt;div class="section" id="le-minimum-requis"&gt;
&lt;h2&gt;Le minimum requis&lt;/h2&gt;
&lt;p&gt;Pour l'installation de Jenkins, rien de plus simple (&lt;em&gt;sur debian&lt;/em&gt;)&lt;/p&gt;
&lt;pre class="literal-block"&gt;
sudo aptitude install jenkins
&lt;/pre&gt;
&lt;p&gt;Mais il va falloir lui donner de quoi télécharger votre code sur &lt;cite&gt;git&lt;/cite&gt; et parfois compiler les librairies python nécessaires&lt;/p&gt;
&lt;pre class="literal-block"&gt;
sudo aptitude install git-core
sudo aptitude install python-dev build-essential python-virtualenv
&lt;/pre&gt;
&lt;p&gt;Les plugins indispensables :&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;covertura&lt;/li&gt;
&lt;li&gt;Violations&lt;/li&gt;
&lt;li&gt;GIT&lt;/li&gt;
&lt;li&gt;Green Balls&lt;/li&gt;
&lt;li&gt;Continuous Integration Game&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="organisation-du-projet-django"&gt;
&lt;h2&gt;Organisation du projet Django&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p class="first"&gt;Définition des dépendances globales dans &lt;cite&gt;requirements.txt&lt;/cite&gt;&lt;/p&gt;
&lt;pre class="literal-block"&gt;
Django&amp;gt;=1.3
south
&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;Définition des dépendances liées aux tests dans &lt;cite&gt;requirements-testing.txt&lt;/cite&gt;&lt;/p&gt;
&lt;pre class="literal-block"&gt;
django-jenkins
&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;Ajout d'un fichier &lt;cite&gt;pylint.rc&lt;/cite&gt; pour régler les niveaux d'alerte &lt;a class="reference external" href="http://www.python.org/dev/peps/pep-0008/"&gt;PEP-8&lt;/a&gt;&lt;/p&gt;
&lt;pre class="literal-block"&gt;
[MESSAGES CONTROL]
disable=E1101,E1103,C0111,I0011,I0012,W0704,W0142,W0212,W0232,W0613,W0702,R0201
...
...
&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;Modèle de settings de tests dans &lt;cite&gt;project/test_settings.py&lt;/cite&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;default_settings&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="n"&gt;DEBUG&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
&lt;span class="n"&gt;TEMPLATE_DEBUG&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DEBUG&lt;/span&gt;

&lt;span class="n"&gt;INSTALLED_APPS&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;&amp;#39;django_jenkins&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;PYLINT_RCFILE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PROJECT_ROOT_PATH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;..&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;conf&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;pylint.rc&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="configuration-du-job-jenkins"&gt;
&lt;h2&gt;Configuration du job Jenkins&lt;/h2&gt;
&lt;p&gt;Les informations de la présentation de Nicolas suffisent pour démarrer.&lt;/p&gt;
&lt;p&gt;J'ai noté cependant qu'il fallait lancer &lt;cite&gt;manage.py&lt;/cite&gt; depuis un répertoire parent au projet pour que l'exploration du code source fonctionne.&lt;/p&gt;
&lt;p&gt;Pour profiter de la magie des ingrédients précédents, nous aurons donc juste à ajouter un bloc script shell, qui installe les dépendances listées, pose les settings de test et migre la base (avec &lt;a class="reference external" href="http://south.aeracode.org"&gt;South&lt;/a&gt;):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c"&gt;#!/bin/bash -ex&lt;/span&gt;
virtualenv --quiet ve
&lt;span class="nb"&gt;source&lt;/span&gt; ./ve/bin/activate
pip install -E ./ve -r &lt;span class="nv"&gt;$WORKSPACE&lt;/span&gt;/requirements.txt
pip install -E ./ve -r &lt;span class="nv"&gt;$WORKSPACE&lt;/span&gt;/requirements-testing.txt
cp &lt;span class="nv"&gt;$WORKSPACE&lt;/span&gt;/project/test_settings.py &lt;span class="nv"&gt;$WORKSPACE&lt;/span&gt;/project/local_settings.py
python &lt;span class="nv"&gt;$WORKSPACE&lt;/span&gt;/project/manage.py syncdb --noinput
python &lt;span class="nv"&gt;$WORKSPACE&lt;/span&gt;/project/manage.py migrate
deactivate
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;et celui-ci pour lancer les tests proprements dits :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c"&gt;#!/bin/bash -ex&lt;/span&gt;
virtualenv --quiet ve
&lt;span class="nb"&gt;source&lt;/span&gt; ./ve/bin/activate
python &lt;span class="nv"&gt;$WORKSPACE&lt;/span&gt;/project/manage.py jenkins yourapps
deactivate
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="pour-un-projet-sig"&gt;
&lt;h2&gt;Pour un projet SIG&lt;/h2&gt;
&lt;p&gt;Il faut installer certaines librairies SIG sur le serveur Jenkins.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;sudo aptitude install libproj0 libgeos-c1
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Si le besoin de cloisonner ces librairies pour chaque projet se fait ressentir, il faut utiliser des outils comme &lt;a class="reference external" href="http://www.minitage.org"&gt;minitage&lt;/a&gt;.&lt;/p&gt;
&lt;div class="section" id="spatialite-au-lieu-de-postgis-comme-base-de-tests"&gt;
&lt;h3&gt;Spatialite au lieu de PostGIS comme base de tests&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;sudo aptitude install python-sqlite libspatialite2 sqlite3
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Script d'initialisation&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;wget http://www.gaia-gis.it/spatialite/init_spatialite-2.3.zip -O /tmp/init_spatialite-2.3.zip
&lt;span class="nb"&gt;cd&lt;/span&gt; /usr/local/lib/
sudo unzip /tmp/init_spatialite-2.3.zip
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;avec dans &lt;cite&gt;test_settings.py&lt;/cite&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;DATABASES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="s"&gt;&amp;#39;default&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;&amp;#39;ENGINE&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;django.contrib.gis.db.backends.spatialite&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;

&lt;span class="n"&gt;SPATIALITE_SQL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;usr&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;local&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;lib&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;init_spatialite-2.3.sql&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Si pysqlite n'a pas été compilé avec les extensions C (Erreur: &lt;em&gt;The pysqlite library does not support C extension loading.&lt;/em&gt;) il va falloir le recompiler !&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;sudo aptitude install libsqlite3-dev
wget http://pysqlite.googlecode.com/files/pysqlite-2.6.3.tar.gz
tar -zxvf pysqlite-2.6.3.tar.gz
&lt;span class="nb"&gt;cd &lt;/span&gt;pysqlite-2.6.3
sed -i s/define&lt;span class="o"&gt;=&lt;/span&gt;SQLITE_OMIT_LOAD_EXTENSION/#define&lt;span class="o"&gt;=&lt;/span&gt;SQLITE_OMIT_LOAD_EXTENSION/g setup.cfg

&lt;span class="nb"&gt;source&lt;/span&gt; ./ve/bin/activate
python setup.py install
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="pour-un-projet-celery"&gt;
&lt;h2&gt;Pour un projet Celery&lt;/h2&gt;
&lt;div class="section" id="kombu-au-lieu-de-rabbitmq-comme-gestionnaire-de-messages"&gt;
&lt;h3&gt;Kombu au lieu de RabbitMQ comme gestionnaire de messages&lt;/h3&gt;
&lt;p&gt;&lt;cite&gt;requirements-testing.txt&lt;/cite&gt;&lt;/p&gt;
&lt;pre class="literal-block"&gt;
kombu
djkombu
&lt;/pre&gt;
&lt;p&gt;&lt;cite&gt;test_settings.py&lt;/cite&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;INSTALLED_APPS&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;&amp;#39;djkombu&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;CARROT_BACKEND&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;django&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Pour désactiver la parallélisation lors des tests&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;CELERY_ALWAYS_EAGER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
</summary><category term="django"></category><category term="jenkins"></category><category term="continuous integration"></category><category term=""></category></entry><entry><title>landez : fabriquer facilement des fichiers MBTiles en python</title><link href="http://blog.mathieu-leplatre.info/landez-fabriquer-facilement-des-fichiers-mbtiles-en-python-fr.html" rel="alternate"></link><updated>2011-04-21T12:04:00+02:00</updated><author><name>Mathieu Leplatre</name></author><id>http://blog.mathieu-leplatre.info/landez-fabriquer-facilement-des-fichiers-mbtiles-en-python-fr.html</id><summary type="html">&lt;p&gt;&lt;a class="reference external" href="http://www.makina-corpus.org/blog/integration-mbtiles-format-android"&gt;Une nouvelle fois&lt;/a&gt;,
Makina Corpus se rapproche du projet &lt;a class="reference external" href="http://mapbox.com/"&gt;MapBox&lt;/a&gt;, avec une contribution
sur la librairie &lt;a class="reference external" href="https://github.com/mapbox/mbutil/contributors"&gt;mbutil&lt;/a&gt;, qui permet de fabriquer des fichiers MBTiles.&lt;/p&gt;
&lt;p&gt;Nous l'utilisons dans &lt;a class="reference external" href="https://github.com/makinacorpus/landez"&gt;landez&lt;/a&gt;, un outil qui permet
de créer des fichiers MBTiles à partir de sites de tuiles externes ou de feuilles de styles Mapnik.&lt;/p&gt;
&lt;p&gt;Son utilisation est fort simple !&lt;/p&gt;
&lt;p&gt;Pour un service de tuiles externe :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;landez&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;MBTilesBuilder&lt;/span&gt;

&lt;span class="c"&gt;# downloads from Cloudmade by default, be careful with terms of usage  !&lt;/span&gt;
&lt;span class="n"&gt;mb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MBTilesBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;remote&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;dest.mbtiles&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;mb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_coverage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bbox&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;90.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;180.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;180.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;90.0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="n"&gt;zoomlevels&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="n"&gt;mb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Avec une feuille de style locale :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;landez&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;MBTilesBuilder&lt;/span&gt;

&lt;span class="n"&gt;mb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MBTilesBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stylefile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;yourstyle.xml&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;dest.mbtiles&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;mb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_coverage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bbox&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;90.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;180.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;180.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;90.0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="n"&gt;zoomlevels&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="n"&gt;mb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Une branche experimentale a été initiée pour travailler sur le multiprocessing
afin de paralléliser au maximum la fabrication des tuiles en amont. Si cela vous intéresse, soyez les bienvenus !&lt;/p&gt;
</summary><category term="python"></category><category term="mapbox"></category><category term="gis"></category><category term="landez"></category></entry><entry><title>Deploy Django behind a reverse proxy</title><link href="http://blog.mathieu-leplatre.info/deploy-django-behind-a-reverse-proxy.html" rel="alternate"></link><updated>2011-04-19T00:00:00+02:00</updated><author><name>Mathieu Leplatre</name></author><id>http://blog.mathieu-leplatre.info/deploy-django-behind-a-reverse-proxy.html</id><summary type="html">&lt;p&gt;By default, Django will assume that your root URL is the root (&lt;cite&gt;/&lt;/cite&gt;) of your domain.&lt;/p&gt;
&lt;p&gt;Using a &lt;a class="reference external" href="http://en.wikipedia.org/wiki/Reverse_proxy"&gt;reverse proxy&lt;/a&gt;, we can run multiple django instances on the same server, using the same domain. (&lt;cite&gt;http://server.org/site1/&lt;/cite&gt;, &lt;cite&gt;http://server.org/site2/&lt;/cite&gt;, ...)&lt;/p&gt;
&lt;p&gt;Many redirects of your application will then be broken (most notable is validation of login form). You can fix that by forcing the root URL in your settings&lt;/p&gt;
&lt;pre class="literal-block"&gt;
FORCE_SCRIPT_NAME = '/site1'
&lt;/pre&gt;
&lt;p&gt;If you use &lt;a class="reference external" href="https://github.com/dcramer/django-sentry"&gt;Sentry&lt;/a&gt;, you'll also have to set&lt;/p&gt;
&lt;pre class="literal-block"&gt;
SENTRY_URL_PREFIX = '/site1'
&lt;/pre&gt;
</summary><category term="tips"></category><category term="deployment"></category><category term="django"></category></entry><entry><title>Ajouter un sélecteur de couches (layer switcher) à polymaps</title><link href="http://blog.mathieu-leplatre.info/ajouter-un-selecteur-de-couches-layer-switcher-a-polymaps-fr.html" rel="alternate"></link><updated>2011-03-09T12:03:00+01:00</updated><author><name>Mathieu Leplatre</name></author><id>http://blog.mathieu-leplatre.info/ajouter-un-selecteur-de-couches-layer-switcher-a-polymaps-fr.html</id><summary type="html">&lt;p&gt;Je fais partie de ceux qui sont persuadés que &lt;a class="reference external" href="http://polymaps.org/"&gt;polymaps&lt;/a&gt; est tout à fait mature !
Certes, il ne fournit pas autant de fonctionnalités et de connecteurs qu'OpenLayers,
mais il ne semble pas que ce soit son objectif ! Il est léger et personnalisable à souhait !&lt;/p&gt;
&lt;p&gt;Pour le prouver, nous allons créer ici un sélecteur de couches pour polymaps.&lt;/p&gt;
&lt;p&gt;Javascript n'est pas mon langage de prédilection, encore moins pour faire
de la programmation orientée objets.&lt;/p&gt;
&lt;p&gt;Voici ce que j'ai réussi à comprendre de l'héritage et la portée dans le modèle objet de polymaps :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;po&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;po&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;self&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;      &lt;span class="c1"&gt;// new class or inheritance&lt;/span&gt;
        &lt;span class="nx"&gt;member&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;         &lt;span class="c1"&gt;// member variable&lt;/span&gt;

    &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;privatemethod&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// [...]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classmethod&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// [...]&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// allows to chain method calls&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;})(&lt;/span&gt;&lt;span class="nx"&gt;org&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;polymaps&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Pour faire ce sélecteur de couches, nous aurons besoin d'une classe disposant :&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;de variables membres qui stockent la liste de couches disponibles (&lt;tt class="docutils literal"&gt;layers&lt;/tt&gt;) et la couche actuelle (&lt;tt class="docutils literal"&gt;current&lt;/tt&gt;)&lt;/li&gt;
&lt;li&gt;d'une méthode de classe qui bascule d'une couche à l'autre&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;switchto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;l&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;  &lt;span class="c1"&gt;// find layer by name&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;l&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nx"&gt;l&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;visible&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;   &lt;span class="c1"&gt;// if already loaded, make it visible&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;l&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;        &lt;span class="c1"&gt;// else load it&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;visible&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// hide current&lt;/span&gt;
    &lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;l&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;d'une méthode qui crée l'interface avec les radio buttons et qui les relie à la méthode précedente&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;elt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;div&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// [...]&lt;/span&gt;
    &lt;span class="c1"&gt;// For each layer, create a &amp;lt;input&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;input&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;type&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;radio&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;value&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="c1"&gt;// [...]&lt;/span&gt;
        &lt;span class="c1"&gt;// Link onChange event on radio&lt;/span&gt;
        &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onchange&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;switchto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;value&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;
        &lt;span class="c1"&gt;// [...]&lt;/span&gt;
        &lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// [...]&lt;/span&gt;
    &lt;span class="nx"&gt;elt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Maintenant il suffit de l'utiliser ! Voici un exemple simple avec deux couches :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c1"&gt;// Create a normal map&lt;/span&gt;
&lt;span class="nx"&gt;map&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;po&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mcmap&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;map&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;po&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;svg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;svg&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;po&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;interact&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="c1"&gt;// Define the layers&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;layers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;&amp;quot;layer1&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="nx"&gt;po&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;po&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;http://server1/{Z}/{X}/{Y}.png&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;l1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;

    &lt;span class="s2"&gt;&amp;quot;layer2&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="nx"&gt;po&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;po&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;http://server2/{Z}/{X}/{Y}.png&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;l2&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Add the default one&lt;/span&gt;
&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;layer1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;span class="c1"&gt;// Create the switcher&lt;/span&gt;
&lt;span class="nx"&gt;po&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;switcher&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Fond de carte&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;layerswitcher&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Et voilà ! Nous avons notre sélecteur de couches, avec un code html
tout simple (&lt;tt class="docutils literal"&gt;div&lt;/tt&gt;, &lt;tt class="docutils literal"&gt;input&lt;/tt&gt;, &lt;tt class="docutils literal"&gt;label&lt;/tt&gt;), facile à styler en CSS,
contrairement au &lt;a class="reference external" href="http://pastebin.com/LQPBv6tZ"&gt;gros pavé généré par le *LayerSwitcher* d'OpenLayers&lt;/a&gt;.&lt;/p&gt;
&lt;img alt="images/polymaps-switcher.png" src="images/polymaps-switcher.png" /&gt;
&lt;p&gt;Pour accéder au code complet et l'améliorer : &amp;quot;&lt;a class="reference external" href="https://github.com/makinacorpus/polymaps-extensions"&gt;Fork me on GitHub&lt;/a&gt;&amp;quot; !&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Article original publié chez&lt;/em&gt; &lt;a class="reference external" href="http://www.makina-corpus.org/blog/ajouter-un-s%C3%A9lecteur-de-couches-layer-switcher-%C3%A0-polymaps"&gt;Makina Corpus&lt;/a&gt;&lt;/p&gt;
</summary><category term="polymaps"></category><category term="tips"></category><category term="javascript"></category><category term="gis"></category></entry><entry><title>Afficher des pictogrammes avec polymaps</title><link href="http://blog.mathieu-leplatre.info/afficher-des-pictogrammes-avec-polymaps-fr.html" rel="alternate"></link><updated>2011-02-28T17:02:00+01:00</updated><author><name>Mathieu Leplatre</name></author><id>http://blog.mathieu-leplatre.info/afficher-des-pictogrammes-avec-polymaps-fr.html</id><summary type="html">&lt;p&gt;En reprenant l'exemple de l'&lt;a class="reference external" href="http://www.makina-corpus.org/blog/afficher-les-donn%C3%A9es-de-paris-opendata-avec-polymaps"&gt;épisode précédent avec polymaps&lt;/a&gt;, nous allons maintenant afficher des pictogrammes sur les points.&lt;/p&gt;
&lt;p&gt;On conserve la couche GeoJSON en utilisant un &lt;a class="reference external" href="http://fr.wikipedia.org/wiki/Fonction_de_rappel"&gt;callback&lt;/a&gt; pour l'évènement &lt;tt class="docutils literal"&gt;load&lt;/tt&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;po&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;geoJson&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
          &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;collecteurs.json&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;load&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;load&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Dans la fonction &lt;tt class="docutils literal"&gt;load()&lt;/tt&gt;, nous allons remplacer les cercles dessinés par défaut par des pictogrammes en manipulant les éléments de la page (&lt;a class="reference external" href="http://fr.wikipedia.org/wiki/Document_Object_Model"&gt;DOM&lt;/a&gt;).
Nous utilisons ici la variable &lt;tt class="docutils literal"&gt;n$&lt;/tt&gt;, qui provient du miniscript &lt;tt class="docutils literal"&gt;nns.js&lt;/tt&gt; livré dans l'archive &lt;em&gt;polymaps&lt;/em&gt; et qui facilite la manipulation du DOM (le vénérable &lt;a class="reference external" href="http://jquery.com/"&gt;jquery&lt;/a&gt; ferait aussi l'affaire)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;ICONSIZE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// Parcourir les features de la carte&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;features&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;circle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;n$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;features&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;circle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;attributes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;features&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;// Ajouter et positionner le pictogramme&lt;/span&gt;
        &lt;span class="c1"&gt;// (à partir de la position du cercle)&lt;/span&gt;
        &lt;span class="nx"&gt;img&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;svg:image&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
             &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;width&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ICONSIZE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
             &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;height&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ICONSIZE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
             &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;transform&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;circle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;transform&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                            &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39; translate(-&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ICONSIZE&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;,&amp;#39;&lt;/span&gt;
                                       &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;-&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ICONSIZE&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="c1"&gt;// Enlever le cercle original&lt;/span&gt;
        &lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;circle&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="c1"&gt;// Définir le chemin du pictogramme à utiliser&lt;/span&gt;
        &lt;span class="c1"&gt;// en fonction de l&amp;#39;attribut&lt;/span&gt;
        &lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;xlink:href&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;attributes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Etat&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Actif&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt;
                               &lt;span class="s1"&gt;&amp;#39;actif.svg&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;inactif.svg&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;img alt="images/polymaps-pictogrammes.jpg" src="images/polymaps-pictogrammes.jpg" /&gt;
&lt;p&gt;&lt;em&gt;© City of Paris, ODBL, CloudMade, OpenStreetMap contributors, CCBYSA&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Ici, nous avons utilisé des pictogrammes SVG, mais le même code fonctionne avec des images PNG ou JPG...&lt;/p&gt;
</summary><category term="javascript"></category><category term="polymaps"></category><category term="gis"></category></entry><entry><title>Afficher les données de Paris OpenData avec polymaps</title><link href="http://blog.mathieu-leplatre.info/afficher-les-donnees-de-paris-opendata-avec-polymaps-fr.html" rel="alternate"></link><updated>2011-02-24T13:02:00+01:00</updated><author><name>Mathieu Leplatre</name></author><id>http://blog.mathieu-leplatre.info/afficher-les-donnees-de-paris-opendata-avec-polymaps-fr.html</id><summary type="html">&lt;p&gt;En ouvrant l'accès à un catalogue de données diverses (Équipements, bâti, arbres d'alignement, arrêtés municipaux, ...)
l'initiative &lt;a class="reference external" href="http://opendata.paris.fr"&gt;ParisData&lt;/a&gt;, l'Open Data de la capitale, nous donne l'occasion de manipuler des données georéférencées.
Notre objectif ici sera de les publier sur une page Web grâce à un outil simple et léger : &lt;a class="reference external" href="http://polymaps.org"&gt;polymaps&lt;/a&gt;.&lt;/p&gt;
&lt;div class="section" id="transformation"&gt;
&lt;h2&gt;Transformation&lt;/h2&gt;
&lt;p&gt;Le système de projection utilisé pour certaines données du catalogue est la &lt;a class="reference external" href="http://en.wikipedia.org/wiki/Lambert_conformal_conic_projection"&gt;Lambert Conformal Conic&lt;/a&gt; (NTF, EPSG 9802)&lt;/p&gt;
&lt;p&gt;Dans la mesure où nous voulons déployer quelquechose de très simple, nous n'avons pas l'intention de sortir la grosse artillerie habituelle (Serveur WMS, Mapserver, QGIS MapServer, ...), nous allons plutôt utiliser un fichier GeoJSON, en longitudes/latitudes WGS84 (EPSG:4326).&lt;/p&gt;
&lt;p&gt;Pour cela, la bibliothèque &lt;a class="reference external" href="http://www.gdal.org"&gt;GDAL&lt;/a&gt; nous offre tous les outils adéquates:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Ouvrir le fichier shape (ESRI Shapefile) fourni par ParisData&lt;/li&gt;
&lt;li&gt;Reprojetter en EPSG:4326&lt;/li&gt;
&lt;li&gt;Choisir les données (attributaires) que nous allons conserver&lt;/li&gt;
&lt;li&gt;Exporter en GeoJSON&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Pour notre exemple, nous avons choisi les emplacements des &lt;a class="reference external" href="http://opendata.paris.fr/opendata/jsp/site/Portal.jsp?document_id=57&amp;amp;portlet_id=106"&gt;points de collecte de verre&lt;/a&gt;.
Parmis les champs fournis, nous choisissons de ne conserver que leur état (&lt;tt class="docutils literal"&gt;Lb_Etat_E&lt;/tt&gt;) et le nom de leur emplacement (&lt;tt class="docutils literal"&gt;Emplacemnt&lt;/tt&gt;).&lt;/p&gt;
&lt;p&gt;Comme python est notre language préféré, et que c'est toujours un plaisir de le montrer en action, voici la petite procédure qui fait tout ça :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c"&gt;# python gdal&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;osgeo&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ogr&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;osgeo&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;osr&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="c"&gt;# Ouvrir le répertoire contenant les shape&lt;/span&gt;
&lt;span class="n"&gt;source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ogr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;INPUT_FOLDER&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# La projection de sortie&lt;/span&gt;
&lt;span class="n"&gt;spatialRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;osr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SpatialReference&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;spatialRef&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ImportFromEPSG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4326&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# Le fichier de sortie&lt;/span&gt;
&lt;span class="n"&gt;driver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ogr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetDriverByName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;GeoJSON&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;shape&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreateDataSource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OUTPUT_FILE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# Parcourir les couches&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;layer&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c"&gt;# Reprojection originale -&amp;gt; destination&lt;/span&gt;
    &lt;span class="n"&gt;originalSpatialRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;layer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetSpatialRef&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;coordTransform&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;osr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CoordinateTransformation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;originalSpatialRef&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                                  &lt;span class="n"&gt;spatialRef&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c"&gt;# Choix des champs des données&lt;/span&gt;
    &lt;span class="n"&gt;properties&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ogr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FeatureDefn&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;properties&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddFieldDefn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ogr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FieldDefn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;Etat&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;properties&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddFieldDefn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ogr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FieldDefn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;Emplacement&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="c"&gt;# Créer la nouvelle couche GeoJSON&lt;/span&gt;
    &lt;span class="n"&gt;newLayer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;shape&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreateLayer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;layer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetName&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;spatialRef&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;# Parcourir les features&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;feature&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c"&gt;# Créer la nouvelle feature&lt;/span&gt;
        &lt;span class="n"&gt;newFeature&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ogr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Feature&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c"&gt;# Remplir les champs choisis&lt;/span&gt;
        &lt;span class="n"&gt;newFeature&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;Etat&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;feature&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;Lb_Etat_E&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="n"&gt;newFeature&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;Emplacement&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;feature&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;Emplacemnt&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="c"&gt;# Reprojetter la feature&lt;/span&gt;
        &lt;span class="n"&gt;geometry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;feature&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetGeometryRef&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;geometry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Transform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;coordTransform&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c"&gt;# Sauvegarder&lt;/span&gt;
        &lt;span class="n"&gt;newFeature&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetGeometry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;geometry&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;newLayer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreateFeature&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newFeature&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;newFeature&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Destroy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Nous obtenons en sortie un fichier GeoJSON avec les points en lat / long et les données 'Etat' et 'Emplacement'.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Feature&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;properties&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Etat&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Actif&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Emplacement&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;37 CHATEAU D&amp;#39;EAU ANGLE BOUCHARDON&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;geometry&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Point&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;coordinates&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="mf"&gt;2.358920&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;48.871154&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Feature&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;properties&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Etat&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Actif&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Emplacement&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;13 place de la Nation&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;geometry&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Point&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;coordinates&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="mf"&gt;2.398154&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;48.848723&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Le fichier pèse 174Ko, mais lorsqu'Apache le servira il pèsera 20Ko (grâce à la compression gzip !)&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="affichage"&gt;
&lt;h2&gt;Affichage&lt;/h2&gt;
&lt;p&gt;Nous choisissons d'afficher ces données dans une page avec &lt;a class="reference external" href="http://polymaps.org"&gt;polymaps&lt;/a&gt;. Il s'agit
d'un composant Javascript permettant de créer des cartes interactives.&lt;/p&gt;
&lt;p&gt;Les critères de comparaison avec OpenLayers (OL) sont:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;la légèreté (~30Ko, 10Ko en gzip!)&lt;/li&gt;
&lt;li&gt;la rapiditité d'exécution&lt;/li&gt;
&lt;li&gt;l'utilisation de GeoJSON et SVG (flexibilité et styles)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Cependant, la couverture fonctionnelle n'est absolument pas comparable. Mais pour afficher une carte avec des points, c'est largement suffisant !&lt;/p&gt;
&lt;p&gt;On commence par un fond de carte: &lt;a class="reference external" href="http://cloudmade.com/"&gt;Cloudmade&lt;/a&gt;, dont les tuiles sont dessinées à partir d'&lt;a class="reference external" href="http://www.openstreetmap.org/"&gt;OpenStreetMap&lt;/a&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;po&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;po&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;http://{S}tile.cloudmade.com&amp;quot;&lt;/span&gt;
                  &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;/1a1b06b230af4efdbb989ea99e9841af&amp;quot;&lt;/span&gt;
                  &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;/998/256/{Z}/{X}/{Y}.png&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hosts&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;a.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;b.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;c.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;])));&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;On ajoute ensuite nos données GeoJSON:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;po&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;geoJson&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;collecteurs.json&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Polymaps facilite la personnalisation du dessin en fonction des données. Ici, nous affichons en vert les collecteurs à l'état &amp;quot;Actif&amp;quot; et en rouge les autres.
De même nous mettons leur &amp;quot;Emplacement&amp;quot; en tooltip (&lt;tt class="docutils literal"&gt;svg:title&lt;/tt&gt;, Firefox 4, Chrome, Opera 11).&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;po&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;geoJson&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;collecteurs.json&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;load&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;po&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stylist&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;fill&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                            &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                                 &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Etat&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Actif&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt;
                                        &lt;span class="s1"&gt;&amp;#39;green&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;red&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                            &lt;span class="p"&gt;}))&lt;/span&gt;
                      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                                 &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Emplacement&lt;/span&gt;
                            &lt;span class="p"&gt;}));&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;img alt="images/parisdata-polymaps.jpg" src="images/parisdata-polymaps.jpg" /&gt;
&lt;p&gt;&lt;a class="reference external" href="http://www.makina-corpus.org/demos/mle/parisdata-polymaps/"&gt;Accéder à la page de démonstration&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="conclusion"&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Finalement, l'étape la plus compliquée était de reprojetter les données.
On regrettera donc que l'initiative ParisData les ait publié sous cette forme exotique.&lt;/p&gt;
&lt;p&gt;Comme le soulignait &lt;a class="reference external" href="http://www.biologeek.com/2010/12/ce-nest-pas-la-taille-qui-compte/"&gt;David&lt;/a&gt; : &lt;em&gt;Publieurs de données, concentrez vous sur la qualité, pas la taille, les développeurs vous remercieront !&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;À noter également que nous avons choisi une approche privilégiant la légèreté. Or, plusieurs sources de données de ParisData sont volumineuses et ne pourraient pas être affichées en GeoJSON sans mettre à genoux le navigateur. Nous serions alors contraints de servir les données sous forme de tuiles...&lt;/p&gt;
&lt;/div&gt;
</summary><category term="python"></category><category term="polymaps"></category><category term="gis"></category></entry><entry><title>SQLAlchemy, a brave new World</title><link href="http://blog.mathieu-leplatre.info/sqlalchemy-a-brave-new-world.html" rel="alternate"></link><updated>2011-02-22T15:02:00+01:00</updated><author><name>Mathieu Leplatre</name></author><id>http://blog.mathieu-leplatre.info/sqlalchemy-a-brave-new-world.html</id><summary type="html">&lt;p&gt;&lt;a class="reference external" href="http://www.sqlalchemy.org/"&gt;SQLAlchemy&lt;/a&gt; becomes an essential technology for any python developper interacting with relational databases.
As a Django developper, I have sat on my laurels for long, being completely satisfied with the &lt;a class="reference external" href="http://docs.djangoproject.com/en/dev/topics/db/queries/"&gt;Django ORM&lt;/a&gt;. It was time to explore its challenger.&lt;/p&gt;
&lt;p&gt;First, before it sounds like I crush my favorite framework : when Django ORM was developped, there was no SQLAlchemy, or almost no good python ORM at all.&lt;/p&gt;
&lt;p&gt;Here are some of the things you might want to know first:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Django ORM documentation is clean and well organized&lt;/li&gt;
&lt;li&gt;Dango ORM was not really meant to be used outside django apps&lt;/li&gt;
&lt;li&gt;Django ORM has limitations when it comes to &lt;a class="reference external" href="http://sralab.com/2009/01/14/limitations-of-the-django-orm-10-in-model-inheritance/"&gt;Model&lt;/a&gt; &lt;a class="reference external" href="http://linfiniti.com/2010/03/django-foreign-key-inheritance-solved/"&gt;Inheritance&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Django ORM does not manage models migrations without extra stuff like &lt;a class="reference external" href="http://south.aeracode.org/"&gt;South&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Django ORM support for multiple databases was introduced &lt;a class="reference external" href="http://docs.djangoproject.com/en/dev/topics/db/multi-db/"&gt;in version 1.2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Django ORM does not always manage connection pooling (e.g. &lt;a class="reference external" href="http://code.djangoproject.com/ticket/7732"&gt;with Oracle&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;SQLAlchemy is light and framework independant&lt;/li&gt;
&lt;li&gt;SQLAlchemy is stripped to a minimum set of (clean and well-implemented) features&lt;/li&gt;
&lt;li&gt;SQLAlchemy is very flexible and supports mapping of objects using declarations or metadata&lt;/li&gt;
&lt;li&gt;SQLAlchemy documentation is bloated (API reference is mixed-in with long explanation and use cases)&lt;/li&gt;
&lt;li&gt;SQLAlchemy requires a better knowledge of advanced python mechanisms and architecture&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In order to explore SQLAlchemy (SA) I created &lt;a class="reference external" href="http://pypi.python.org/pypi/pyfspot"&gt;pyfspot&lt;/a&gt; (&lt;a class="reference external" href="https://github.com/leplatrem/pyfspot"&gt;sources are on github&lt;/a&gt;): a very small application to manage the database of the F-Spot photo manager.
It is not supposed to save lives, but that will at least be:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;a pretext for me to dive into the API&lt;/li&gt;
&lt;li&gt;a small and useful tool&lt;/li&gt;
&lt;li&gt;an example of SA in action for any developper interested&lt;/li&gt;
&lt;li&gt;a base for a full &lt;a class="reference external" href="http://f-spot.org/"&gt;F-Spot&lt;/a&gt; management application (&lt;tt class="docutils literal"&gt;&amp;lt;/dreamer&amp;gt;&lt;/tt&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I discovered a few concrete things:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Django inspectdb equivalent ?&lt;ul&gt;
&lt;li&gt;&lt;a class="reference external" href="http://code.google.com/p/sqlautocode/"&gt;sqlautocode&lt;/a&gt; (unfortunately &lt;a class="reference external" href="http://code.google.com/p/sqlautocode/issues/detail?id=32"&gt;I could not use it&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Django fixtures equivalent ?&lt;ul&gt;
&lt;li&gt;&lt;a class="reference external" href="http://code.google.com/p/fixture/"&gt;fixture&lt;/a&gt; (&lt;a class="reference external" href="http://farmdev.com/projects/fixture/using-loadable-fixture.html#an-example-of-loading-data-using-sqlalchemy"&gt;demo&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Django &lt;cite&gt;model.DoesNotExist&lt;/cite&gt; ?&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c"&gt;# get() does not throw exception&lt;/span&gt;
&lt;span class="n"&gt;tag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Tag&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c"&gt;# filter().one() does ...&lt;/span&gt;
&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;tag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Photo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filter_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1337&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;one&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;sqlalchemy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;orm&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NoResultFound&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c"&gt;# d&amp;#39;oh!&lt;/span&gt;
    &lt;span class="k"&gt;pass&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Invert condition like Django exclude() ?&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Photo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;Photo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;base_uri&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;endswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;/&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Escape LIKE condition ?&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;Photo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;base_uri&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;like&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;%&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="si"&gt;%%&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;escape&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Intersections of many-to-many ?&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c"&gt;# A tag&lt;/span&gt;
&lt;span class="n"&gt;tag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Tag&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filter_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;foo&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;one&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="c"&gt;# A set of photos&lt;/span&gt;
&lt;span class="n"&gt;photoset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Photo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;Photo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;base_uri&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;endswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;/&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="c"&gt;# intersect() won&amp;#39;t work&lt;/span&gt;
&lt;span class="n"&gt;photoset&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;intersect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;photos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="ne"&gt;AttributeError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;InstrumentedList&amp;#39;&lt;/span&gt; &lt;span class="nb"&gt;object&lt;/span&gt; &lt;span class="n"&gt;has&lt;/span&gt; &lt;span class="n"&gt;no&lt;/span&gt; &lt;span class="n"&gt;attribute&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;c&amp;#39;&lt;/span&gt;
&lt;span class="c"&gt;# Use any()&lt;/span&gt;
&lt;span class="n"&gt;photoset&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Photo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Well, those were my first steps. As expected, it did not feel so well to relearn how to walk. But at least I am now ready to get my bearings in SQLAlchemy's world.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Original post at&lt;/em&gt; &lt;a class="reference external" href="http://www.makina-corpus.org/blog/sqlalchemy-brave-new-world"&gt;Makina Corpus&lt;/a&gt;&lt;/p&gt;
</summary><category term="python"></category><category term="django"></category><category term="sqlalchemy"></category></entry><entry><title>Javascript Beautifier in command-line (and in Geany editor)</title><link href="http://blog.mathieu-leplatre.info/javascript-beautifier-in-command-line-and-in-geany-editor.html" rel="alternate"></link><updated>2011-02-01T10:20:00+01:00</updated><author><name>Mathieu Leplatre</name></author><id>http://blog.mathieu-leplatre.info/javascript-beautifier-in-command-line-and-in-geany-editor.html</id><summary type="html">&lt;p&gt;Install a Javascript engine (like Mozilla Rhino)&lt;/p&gt;
&lt;pre class="literal-block"&gt;
sudo aptitude install rhino
&lt;/pre&gt;
&lt;p&gt;Get the beautifier script (put it somewhere like &lt;cite&gt;~/.bin&lt;/cite&gt;)&lt;/p&gt;
&lt;pre class="literal-block"&gt;
wget http://jsbeautifier.org/beautify.js
&lt;/pre&gt;
&lt;p&gt;Add the following at the end of &lt;cite&gt;beautify.js&lt;/cite&gt;&lt;/p&gt;
&lt;pre class="literal-block"&gt;
print( js_beautify( readFile( arguments[0] )));
&lt;/pre&gt;
&lt;p&gt;Create a shell script that will call it (like &lt;cite&gt;~/.bin/beautifyjs&lt;/cite&gt;)&lt;/p&gt;
&lt;pre class="literal-block"&gt;
#!/bin/sh
java -cp /usr/share/java/js.jar org.mozilla.javascript.tools.shell.Main ~/.bin/beautify.js $*
&lt;/pre&gt;
&lt;p&gt;Make sure to set it executable&lt;/p&gt;
&lt;pre class="literal-block"&gt;
chmod +x ~/.bin/beautifyjs
&lt;/pre&gt;
&lt;div class="section" id="use-it-from-command-line"&gt;
&lt;h2&gt;Use it from command-line&lt;/h2&gt;
&lt;p&gt;At least to check that it works !&lt;/p&gt;
&lt;pre class="literal-block"&gt;
~/.bin/beautifyjs /your/file.js
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="or-in-geany-editor"&gt;
&lt;h2&gt;Or in Geany Editor&lt;/h2&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p class="first"&gt;Open a Javascript file&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;Open menu &lt;em&gt;Build&lt;/em&gt; &amp;gt; &lt;em&gt;Define Build Commands&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;Create a new entry (like &lt;cite&gt;beautify&lt;/cite&gt;)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;In command, enter the following&lt;/p&gt;
&lt;pre class="literal-block"&gt;
~/.bin/beautifyjs %f &amp;gt; /tmp/tmpfile.js &amp;amp;&amp;amp; geany /tmp/tmpfile.js
&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;In working directory, enter &lt;cite&gt;%d&lt;/cite&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;/div&gt;
</summary><category term="tips"></category><category term="javascript"></category></entry><entry><title>Python UTF-8 print fails when redirecting stdout</title><link href="http://blog.mathieu-leplatre.info/python-utf-8-print-fails-when-redirecting-stdout.html" rel="alternate"></link><updated>2011-01-26T11:25:00+01:00</updated><author><name>Mathieu Leplatre</name></author><id>http://blog.mathieu-leplatre.info/python-utf-8-print-fails-when-redirecting-stdout.html</id><summary type="html">&lt;p&gt;Consider the following piece of code:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c"&gt;# -*- coding: utf-8 -*-&lt;/span&gt;
&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;u&amp;quot;Վարդանաշեն&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Running this in a terminal works:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;python test.py
Վարդանաշեն
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Redirecting standard output to a file &lt;strong&gt;fails&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;python test.py &amp;gt; file
Traceback &lt;span class="o"&gt;(&lt;/span&gt;most recent call last&lt;span class="o"&gt;)&lt;/span&gt;:
  File &lt;span class="s2"&gt;&amp;quot;test.py&amp;quot;&lt;/span&gt;, line 2, in &amp;lt;module&amp;gt;
    print u&lt;span class="s2"&gt;&amp;quot;Վարդանաշեն&amp;quot;&lt;/span&gt;
UnicodeEncodeError: &lt;span class="s1"&gt;&amp;#39;ascii&amp;#39;&lt;/span&gt; codec can&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;t encode characters in position 0-9: ordinal not in range&lt;span class="o"&gt;(&lt;/span&gt;128&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;a class="reference external" href="http://wiki.python.org/moin/PrintFails"&gt;Explanations are available on Python official wiki&lt;/a&gt;: default encoding has to be forced.&lt;/p&gt;
&lt;p&gt;With an environment variable:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nv"&gt;$ PYTHONIOENCODING&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;utf_8&amp;#39;&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;export &lt;/span&gt;PYTHONIOENCODING
&lt;span class="nv"&gt;$ &lt;/span&gt;python test.py &amp;gt; file
&lt;span class="err"&gt;$&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With source modification:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;sys&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;codecs&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;locale&lt;/span&gt;
&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;codecs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getwriter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;locale&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getpreferredencoding&lt;/span&gt;&lt;span class="p"&gt;())(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
</summary><category term="python"></category><category term="encoding"></category><category term="shell"></category></entry><entry><title>Grep with context lines above and below</title><link href="http://blog.mathieu-leplatre.info/grep-with-context-lines-above-and-below.html" rel="alternate"></link><updated>2010-09-30T10:25:00+02:00</updated><author><name>Mathieu Leplatre</name></author><id>http://blog.mathieu-leplatre.info/grep-with-context-lines-above-and-below.html</id><summary type="html">&lt;p&gt;I was about to write a script to implement exactly what already exists natively in GNU &lt;cite&gt;grep&lt;/cite&gt;, a blasphemy I got saved from by my workmates.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;grep --line-number --colour&lt;span class="o"&gt;=&lt;/span&gt;AUTO --before-context 5 --after-context 5 PATTERN FILENAME
&lt;/pre&gt;&lt;/div&gt;
&lt;img alt="images/grep-lines.png" src="images/grep-lines.png" /&gt;
</summary><category term="tips"></category><category term="shell"></category></entry><entry><title>Python lazy hasattr()</title><link href="http://blog.mathieu-leplatre.info/python-lazy-hasattr.html" rel="alternate"></link><updated>2010-09-30T10:20:00+02:00</updated><author><name>Mathieu Leplatre</name></author><id>http://blog.mathieu-leplatre.info/python-lazy-hasattr.html</id><summary type="html">&lt;p&gt;Python &lt;cite&gt;hasattr()&lt;/cite&gt; evaluates the specified attribute, which may not be desired !&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__get__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;obs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;evaluated&amp;quot;&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ClassA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Attr&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="nd"&gt;@property&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;b&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;evaluated&amp;quot;&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ClassA&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;
&lt;span class="n"&gt;evaluated&lt;/span&gt;
&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;
&lt;span class="n"&gt;evaluated&lt;/span&gt;
&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now note that &lt;cite&gt;hasattr()&lt;/cite&gt; evaluates the lazy attribute !&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;hasattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;evaluated&lt;/span&gt;
&lt;span class="bp"&gt;True&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;hasattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;b&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;evaluated&lt;/span&gt;
&lt;span class="bp"&gt;True&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Let us fix that !&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;lazyhasattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__dict__&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                   &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__class__&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__dict__&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ClassA&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;lazyhasattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="bp"&gt;True&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;lazyhasattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;b&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="bp"&gt;True&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
</summary><category term="tips"></category><category term="python"></category></entry><entry><title>Python check arguments types</title><link href="http://blog.mathieu-leplatre.info/python-check-arguments-types.html" rel="alternate"></link><updated>2010-06-10T11:25:00+02:00</updated><author><name>Mathieu Leplatre</name></author><id>http://blog.mathieu-leplatre.info/python-check-arguments-types.html</id><summary type="html">&lt;p&gt;Decorators help us wrap some routines at function invocation. Here I show a small example that raises &lt;cite&gt;TypeError&lt;/cite&gt; exceptions when given args have unexpected type. Note that &lt;strong&gt;it is not pythonic to type check&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;This recipe is quite old, as its first pieces appear in &lt;a class="reference external" href="http://www.python.org/dev/peps/pep-0318/"&gt;PEP-0318&lt;/a&gt; in 2003. &lt;a class="reference external" href="http://pypi.python.org/pypi/typecheck"&gt;A module exists too&lt;/a&gt; but it looks neglected...&lt;/p&gt;
&lt;p&gt;The (heretic) decorator itself !&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;accepts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;argstypes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargstypes&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;wrapper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;wrapped&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argstypes&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="ne"&gt;TypeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s"&gt;() takes at most &lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s"&gt; non-keyword arguments (&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s"&gt; given)&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argstypes&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
            &lt;span class="n"&gt;argspairs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;argstypes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;kwargstypes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="ne"&gt;TypeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Unexpected keyword argument &amp;#39;&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s"&gt;&amp;#39; for &lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s"&gt;()&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                &lt;span class="n"&gt;argspairs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;kwargstypes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;argspairs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;param&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="ne"&gt;TypeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Parameter &amp;#39;&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s"&gt;&amp;#39; is not &lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;wrapped&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;wrapper&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Let us decorate !&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nd"&gt;@accepts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg2&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg2&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;     &lt;span class="k"&gt;pass&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;See it in action...&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;foo&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;foo&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg2&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="ne"&gt;TypeError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;takes&lt;/span&gt; &lt;span class="n"&gt;at&lt;/span&gt; &lt;span class="n"&gt;least&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="n"&gt;argument&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="n"&gt;given&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;foo&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;bar&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="ne"&gt;TypeError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;takes&lt;/span&gt; &lt;span class="n"&gt;at&lt;/span&gt; &lt;span class="n"&gt;most&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="n"&gt;non&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;keyword&lt;/span&gt; &lt;span class="n"&gt;arguments&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="n"&gt;given&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;foo&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg2&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;bar&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="ne"&gt;TypeError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Parameter&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;bar&amp;#39;&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;foo&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg3&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;bar&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="ne"&gt;TypeError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Unexpected&lt;/span&gt; &lt;span class="n"&gt;keyword&lt;/span&gt; &lt;span class="n"&gt;argument&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;arg3&amp;#39;&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Or with classes...&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;A&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;     &lt;span class="k"&gt;pass&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;B&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;     &lt;span class="nd"&gt;@accepts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;unicode&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;     &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;         &lt;span class="k"&gt;pass&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;     &lt;span class="nd"&gt;@accepts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;     &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;g&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;         &lt;span class="k"&gt;pass&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;u&amp;#39;foo&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;foo&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="ne"&gt;TypeError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Parameter&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;&amp;lt;__main__.B object at 0x902466c&amp;gt;&amp;#39;&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;A&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The same can be applied to &lt;cite&gt;return&lt;/cite&gt; :)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;returns&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rtype&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;wrapper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;wrapped&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rtype&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="ne"&gt;TypeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;return value &lt;/span&gt;&lt;span class="si"&gt;%r&lt;/span&gt;&lt;span class="s"&gt; does not match &lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;rtype&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;wrapped&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;wrapper&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nd"&gt;@accepts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg2&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="nd"&gt;@returns&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg2&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;     &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;..but kids, don't do this at home :-)&lt;/p&gt;
</summary><category term="python"></category><category term="decorators"></category></entry><entry><title>Filesystem Watch with PyQt4</title><link href="http://blog.mathieu-leplatre.info/filesystem-watch-with-pyqt4.html" rel="alternate"></link><updated>2009-08-14T13:37:00+02:00</updated><author><name>Mathieu Leplatre</name></author><id>http://blog.mathieu-leplatre.info/filesystem-watch-with-pyqt4.html</id><summary type="html">&lt;p&gt;I decided to write a generic program that can watch a folder or some files and run a command when changes occur.&lt;/p&gt;
&lt;p&gt;Most of the work is done by PyQt4's &lt;cite&gt;QFileSystemWatcher&lt;/cite&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;qfsw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;QtCore&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QFileSystemWatcher&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;qfsw&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addPaths&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;path1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;file2&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="n"&gt;QtCore&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QObject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qfsw&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;QtCore&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SIGNAL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;directoryChanged(QString)&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;QtCore&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QObject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qfsw&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;QtCore&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SIGNAL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;fileChanged(QString)&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here is the script&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c"&gt;# !/usr/bin/env python&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# Runs a command when a file system change occurs in specified list of paths.&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# (c) Copyright 2008, Mathieu Leplatre,&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# This software may be used and distributed according to the terms&lt;/span&gt;
&lt;span class="c"&gt;# of the GNU Public License, incorporated herein by reference.&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;PyQt4&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;QtCore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;QtGui&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;signal&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;optparse&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OptionParser&lt;/span&gt;

&lt;span class="c"&gt;# Parse command-line options&lt;/span&gt;
&lt;span class="n"&gt;usage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;&amp;quot;&amp;quot;Usage: %prog [options] COMMAND PATHS&lt;/span&gt;
&lt;span class="s"&gt;Run COMMAND when a file system change occurs in specified list of PATHS.&lt;/span&gt;

&lt;span class="s"&gt;COMMAND can contain &amp;#39;&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s"&gt;&amp;#39; to refer changed file or directory.&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;

&lt;span class="n"&gt;parser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;OptionParser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;usage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%prog 1.0&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse_args&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print_help&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# Command&lt;/span&gt;
&lt;span class="n"&gt;command&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="c"&gt;# List of paths&lt;/span&gt;
&lt;span class="n"&gt;paths&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:]&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;onFileSystemChanged&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="sd"&gt;    Callback when file or folder change&lt;/span&gt;
&lt;span class="sd"&gt;    @param path : Changed path&lt;/span&gt;
&lt;span class="sd"&gt;    @type  path : string&lt;/span&gt;
&lt;span class="sd"&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;global&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt;
    &lt;span class="c"&gt;# Execute command replacing %s with path:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;command&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;
    &lt;span class="c"&gt;# Run as different process&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Run &amp;#39;&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;...&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fork&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;QtGui&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QApplication&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;# Set up file system watcher&lt;/span&gt;
    &lt;span class="n"&gt;qfsw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;QtCore&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QFileSystemWatcher&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;qfsw&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addPaths&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;QtCore&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QObject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qfsw&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;QtCore&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SIGNAL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;directoryChanged(QString)&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="n"&gt;onFileSystemChanged&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;QtCore&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QObject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qfsw&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;QtCore&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SIGNAL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;fileChanged(QString)&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="n"&gt;onFileSystemChanged&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;# Allow program to be interrupted with Ctrl+C&lt;/span&gt;
    &lt;span class="n"&gt;signal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;signal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SIGINT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;signal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SIG_DFL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;# Qt Main loop&lt;/span&gt;
    &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exec_&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;


&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;__main__&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
</summary><category term="qt"></category><category term="pyqt4"></category><category term="python"></category></entry><entry><title>Text extents with Python Cairo</title><link href="http://blog.mathieu-leplatre.info/text-extents-with-python-cairo.html" rel="alternate"></link><updated>2009-08-10T10:20:00+02:00</updated><author><name>Mathieu Leplatre</name></author><id>http://blog.mathieu-leplatre.info/text-extents-with-python-cairo.html</id><summary type="html">&lt;p&gt;I needed this and could not find it. So I share it here (and even better if Google'd index it!)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;textwidth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fontsize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;cairo&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="ne"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;fontsize&lt;/span&gt;
    &lt;span class="n"&gt;surface&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cairo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SVGSurface&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;undefined.svg&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1280&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;cr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cairo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;surface&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;cr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;select_font_face&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;Arial&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cairo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FONT_SLANT_NORMAL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cairo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FONT_WEIGHT_BOLD&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;cr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_font_size&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fontsize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;xbearing&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ybearing&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;xadvance&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;yadvance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text_extents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
</summary><category term="cairo"></category><category term="python"></category></entry><entry><title>Colored Output in Console with Python</title><link href="http://blog.mathieu-leplatre.info/colored-output-in-console-with-python.html" rel="alternate"></link><updated>2008-12-31T13:37:00+01:00</updated><author><name>Mathieu Leplatre</name></author><id>http://blog.mathieu-leplatre.info/colored-output-in-console-with-python.html</id><summary type="html">&lt;p&gt;Playing around with ANSI in a color capable terminal.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c"&gt;#!/usr/bin/env python&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;sys&lt;/span&gt;

&lt;span class="n"&gt;BLACK&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;RED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;GREEN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;YELLOW&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;BLUE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MAGENTA&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CYAN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;WHITE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;#following from Python cookbook, #475186&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;has_colours&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nb"&gt;hasattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;isatty&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isatty&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt; &lt;span class="c"&gt;# auto color only on TTYs&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;curses&lt;/span&gt;
        &lt;span class="n"&gt;curses&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setupterm&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;curses&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tigetnum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;colors&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c"&gt;# guess false in case of error&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
&lt;span class="n"&gt;has_colours&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;has_colours&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;printout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;colour&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;WHITE&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;has_colours&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;seq&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\x1b&lt;/span&gt;&lt;span class="s"&gt;[1;&lt;/span&gt;&lt;span class="si"&gt;%d&lt;/span&gt;&lt;span class="s"&gt;m&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;colour&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\x1b&lt;/span&gt;&lt;span class="s"&gt;[0m&amp;quot;&lt;/span&gt;
                &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;seq&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;A simple demo:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt; &lt;span class="n"&gt;python&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# Test&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="n"&gt;printout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;[debug]   &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;GREEN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;in green&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;printout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;[warning] &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;YELLOW&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;in yellow&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;printout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;[error]   &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;RED&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;in red&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;img alt="images/ansi-color.png" src="images/ansi-color.png" /&gt;
</summary><category term="terminal"></category><category term="python"></category></entry><entry><title>Automatic blog publishing using Python and XML-RPC</title><link href="http://blog.mathieu-leplatre.info/automatic-blog-publishing-using-python-and-xml-rpc.html" rel="alternate"></link><updated>2008-12-01T13:37:00+01:00</updated><author><name>Mathieu Leplatre</name></author><id>http://blog.mathieu-leplatre.info/automatic-blog-publishing-using-python-and-xml-rpc.html</id><summary type="html">&lt;p&gt;The following piece of code collects links in a Pligg database (but could be any kind of source like RSS feed...) and automatically builds and publishes entries in a blog using XML-RPC.&lt;/p&gt;
&lt;p&gt;A small database class :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DatabaseAPI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;localhost&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3306&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;root&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;passwd&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;root123&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;mysql&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;MySQLdb&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MySQLdb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;passwd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;disconnect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fetchall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sqlquery&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;cursor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sqlquery&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fetchall&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;A Blog publishing class :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BlogAPI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;urlapi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;xmlrpclib&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;xmlrpclib&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;xmlrpclib&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;xmlrpclib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ServerProxy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;urlapi&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="ne"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Could not connect to &lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;newPost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;blogid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;publish&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt; &lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;&amp;lt;em&amp;gt;empty entry&amp;lt;/em&amp;gt;&amp;quot;&lt;/span&gt;
        &lt;span class="n"&gt;post&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
        &lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;title&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;
        &lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;description&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;metaWeblog&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;newPost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;blogid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;publish&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;xmlrpclib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fault&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fault&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="ne"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;fault&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;faultString&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Build the SQL query : all entries of current week&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;datetime&lt;/span&gt;
&lt;span class="n"&gt;dt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;timedelta&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;weeks&lt;/span&gt;&lt;span class="o"&gt;=-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;today&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;today&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;agelimit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;today&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;dt&lt;/span&gt;
&lt;span class="n"&gt;stmt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;SELECT link_url, link_url_title&lt;/span&gt;
&lt;span class="s"&gt;FROM pligg_links&lt;/span&gt;
&lt;span class="s"&gt;WHERE link_status = &amp;#39;published&amp;#39; AND link_published_date &amp;gt; &amp;quot;&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;ORDER BY link_published_date DESC&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;agelimit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;strftime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%Y%m&lt;/span&gt;&lt;span class="si"&gt;%d&lt;/span&gt;&lt;span class="s"&gt;000000&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Put everything together :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DatabaseAPI&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;user&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;passwd&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;pass&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;entries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fetchall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stmt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;disconnect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;&amp;lt;ul&amp;gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;    &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;&amp;lt;/ul&amp;gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;

&lt;span class="n"&gt;blog&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BlogAPI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://yourblog/xmlrpc/&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;user&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;pass&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Links week #&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;today&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;strftime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%W&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;blog&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;newPost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
</summary><category term="python"></category><category term="xml-rpc"></category></entry><entry><title>Another success story about Ruby On Rails working with Apache</title><link href="http://blog.mathieu-leplatre.info/another-success-story-about-ruby-on-rails-working-with-apache.html" rel="alternate"></link><updated>2008-08-01T09:12:00+02:00</updated><author><name>Mathieu Leplatre</name></author><id>http://blog.mathieu-leplatre.info/another-success-story-about-ruby-on-rails-working-with-apache.html</id><summary type="html">&lt;p&gt;This procedure does not guarantee anything and should be considered approximate. However this should be fairly enough for someone familiar with Apache environments.&lt;/p&gt;
&lt;div class="section" id="ruby-environment"&gt;
&lt;h2&gt;Ruby environment&lt;/h2&gt;
&lt;p&gt;We install Ruby via apt-get&lt;/p&gt;
&lt;pre class="literal-block"&gt;
sudo apt-get install ruby libzlib-ruby rdoc irb
&lt;/pre&gt;
&lt;p&gt;At this point, you can run Ruby scripts like you did with Python or Perl.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="gems"&gt;
&lt;h2&gt;Gems&lt;/h2&gt;
&lt;p&gt;Gems are like perl's CPAN or PHP's PEAR. We install it from source in order to enjoy the whole Gems repository (instead of being limited to packaged gems only).&lt;/p&gt;
&lt;pre class="literal-block"&gt;
wget &amp;quot;http://rubyforge.org/frs/download.php/38646/rubygems-x.x.x.tgz&amp;quot;
tar -xvzf rubygems-x.x.x.tgz
rm rubygems-x.x.x.tgz
cd rubygems-x.x.x
sudo ruby setup.rb
cd ..
rm -r rubygems-1.2.0
sudo ln -s /usr/bin/gem1.8 /usr/bin/gem
&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;(DO NOT use sudo ruby rubygemsx.x.x/setup.rb)&lt;/em&gt;&lt;/p&gt;
&lt;pre class="literal-block"&gt;
sudo gem update --system
&lt;/pre&gt;
&lt;p&gt;We will install additionnal applications... those depend on your needs. The Gems are compiled on the fly, therefore development packages are usually required along.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="ruby-on-rails"&gt;
&lt;h2&gt;Ruby on Rails&lt;/h2&gt;
&lt;pre class="literal-block"&gt;
sudo gem install rails --include-dependencies
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="mysql-support"&gt;
&lt;h2&gt;Mysql support&lt;/h2&gt;
&lt;pre class="literal-block"&gt;
sudo apt-get install libmysql-ruby libmysqlclient15-dev
sudo gem install mysql
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="imagemagick-support"&gt;
&lt;h2&gt;ImageMagick support&lt;/h2&gt;
&lt;pre class="literal-block"&gt;
sudo apt-get install librmagick-ruby1.8 libmagick9-dev
sudo gem install rmagick
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="integrate-with-apache"&gt;
&lt;h2&gt;Integrate with Apache&lt;/h2&gt;
&lt;pre class="literal-block"&gt;
sudo apt-get install apache2-prefork-dev
&lt;/pre&gt;
&lt;p&gt;Enable additionnal modules&lt;/p&gt;
&lt;pre class="literal-block"&gt;
a2enmod rewrite
a2enmod suexec
a2enmod include
&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;I might have missed some.&lt;/em&gt;. Some tutorials recommend Fast-CGI.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="install-phusion-passenger-mod-rails"&gt;
&lt;h2&gt;Install Phusion Passenger (mod_rails)&lt;/h2&gt;
&lt;p&gt;Usually, RubyOnRails has its own web server (&lt;a class="reference external" href="http://en.wikipedia.org/wiki/Mongrel_(web_server)"&gt;Mongrel&lt;/a&gt;) on port 3000. It is also quite common to have a cluster of processes with load balancing and Apache proxy...&lt;/p&gt;
&lt;p&gt;But you may want to do something very simple that just integrates within Apache. Here comes Phusion Passenger!&lt;/p&gt;
&lt;pre class="literal-block"&gt;
sudo gem install passenger
sudo passenger-install-apache2-module
&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;(following the instructions, or look at the [[http://www.modrails.com/documentation/Users%20guide.html|user guide]]).&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;At the end, the wizard tells you to add some lines in &lt;cite&gt;httpd.conf&lt;/cite&gt;. I recommend the following method instead, which splits those lines into a module that you can enable / disable.&lt;/p&gt;
&lt;p&gt;Create two files :
* /etc/apache2/mods-available/mod_rails.load&lt;/p&gt;
&lt;pre class="literal-block"&gt;
LoadModule passenger_module /usr/lib/ruby/gems/1.8/gems/passenger-2.0.2/ext/apache2/mod_passenger.so
&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p class="first"&gt;/etc/apache2/mods-available/mod_rails.conf&lt;/p&gt;
&lt;pre class="literal-block"&gt;
PassengerRoot /usr/lib/ruby/gems/1.8/gems/passenger-2.0.2
PassengerRuby /usr/bin/ruby1.8
&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Enable this new module&lt;/p&gt;
&lt;pre class="literal-block"&gt;
sudo a2enmod mod_rails
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="create-your-virtualhost"&gt;
&lt;h2&gt;Create your VirtualHost&lt;/h2&gt;
&lt;p&gt;The DocumentRoot must point to the public folder of your Ruby On Rails application.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p class="first"&gt;If your Ruby application is alone, your apache site will be something like this&lt;/p&gt;
&lt;pre class="literal-block"&gt;
&amp;lt;virtualhost *:80&amp;gt;
    ServerName yourapp
    DocumentRoot /var/rails/yourapp/public/
    ErrorLog /var/rails/yourapp/log/apache.log

    &amp;lt;directory /var/rails/yourapp/public&amp;gt;
       Options ExecCGI FollowSymLinks
       AddHandler cgi-script .cgi
       AllowOverride all
       Order allow,deny
       Allow from all
    &amp;lt;/directory&amp;gt;
&amp;lt;/virtualhost&amp;gt;
&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;If you want it a subfolder of your current DocumentRoot, look at this.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;The simplest for me was to setup a sub-domain. Don't forget to update your DNS information.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Relax ! Restart Apache and that's it !&lt;/p&gt;
&lt;/div&gt;
</summary><category term="ruby"></category><category term="howto"></category></entry><entry><title>Apply Debian patches step-by-step</title><link href="http://blog.mathieu-leplatre.info/apply-debian-patches-step-by-step.html" rel="alternate"></link><updated>2008-08-01T09:12:00+02:00</updated><author><name>Mathieu Leplatre</name></author><id>http://blog.mathieu-leplatre.info/apply-debian-patches-step-by-step.html</id><summary type="html">&lt;p&gt;I thought it may be relevant to share the history of commands I used to apply a patch and submit it to &lt;a class="reference external" href="http://launchpad.net"&gt;launchpad&lt;/a&gt;.&lt;/p&gt;
&lt;div class="section" id="get-the-tools"&gt;
&lt;h2&gt;0) Get the tools&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p class="first"&gt;You'll need a working PGP key&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;Install the necessary tools&lt;/p&gt;
&lt;pre class="literal-block"&gt;
sudo apt-get install devscripts dpatch fakeroot dh-make
&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;(I might have forgotten some...)&lt;/em&gt; :)&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="get-the-files"&gt;
&lt;h2&gt;1) Get the files&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p class="first"&gt;Get the last package source, from the package page : &lt;a class="reference external" href="http://packages.ubuntu.com/hardy/exaile"&gt;http://packages.ubuntu.com/hardy/exaile&lt;/a&gt;&lt;/p&gt;
&lt;pre class="literal-block"&gt;
dget -x http://archive.ubuntu.com/ubuntu/pool/universe/e/exaile/exaile_0.2.11.1-0ubuntu3.dsc
&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;Get the patch file&lt;/p&gt;
&lt;pre class="literal-block"&gt;
wget http://launchpadlibrarian.net/9466876/gui_track_filter.patch
&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;Step in the package code&lt;/p&gt;
&lt;pre class="literal-block"&gt;
cd exaile-0.2.11.1/
&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="apply-the-patch"&gt;
&lt;h2&gt;2) Apply the patch&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p class="first"&gt;Have a look at the list of patches in the &lt;cite&gt;debian/patches&lt;/cite&gt; folder&lt;/p&gt;
&lt;pre class="literal-block"&gt;
ls debian/patches/

00list
01_fix_makefile_for_pysupport.dpatch
02_files-on-share-dir.dpatch
03_fix_mmkeys.dpatch
&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;Create yours respecting dpatch filenames pattern (without extension)&lt;/p&gt;
&lt;pre class="literal-block"&gt;
dpatch-edit-patch 04_fix_search_exit
&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;You now have a shell in the &lt;cite&gt;/tmp&lt;/cite&gt; folder.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;Apply the patch file&lt;/p&gt;
&lt;pre class="literal-block"&gt;
patch -p0 &amp;lt; $HOME/Desktop/gui_track_filter.patch
&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;Exit the shell&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="describe-your-changes"&gt;
&lt;h2&gt;3) Describe your changes&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p class="first"&gt;Add your dpatch name in the &lt;cite&gt;00list&lt;/cite&gt; file&lt;/p&gt;
&lt;pre class="literal-block"&gt;
nano debian/patches/00list
&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;Modify Debian changelog using&lt;/p&gt;
&lt;pre class="literal-block"&gt;
dch -i
&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;Your name and signing information will be automatically added.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;Look at previous descriptions and respect their structure.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;Include launchpad bug number with &lt;cite&gt;(LP: #number)&lt;/cite&gt; string&lt;/p&gt;
&lt;pre class="literal-block"&gt;
exaile (0.2.11.1-0ubuntu4) hardy; urgency=low
&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;&lt;cite&gt;debian/patches/04_fix_search_exit.dpatch&lt;/cite&gt;&lt;/p&gt;
&lt;pre class="literal-block"&gt;
debian/patches/00list:
- Fix clean search terms on exit (LP: #95860)

-- Mathieu Leplatre &amp;lt;xxxx&amp;#64;gmail.com&amp;gt;  Tue, 27 May 2008 10:45:42 -0300
&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="create-debdiff"&gt;
&lt;h2&gt;4) Create debdiff&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p class="first"&gt;Create the dsc and diff files using&lt;/p&gt;
&lt;pre class="literal-block"&gt;
debuild -S
cd ..
&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;Step in the package code&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;Create the debdiff file using&lt;/p&gt;
&lt;pre class="literal-block"&gt;
debdiff exaile_0.2.11.1-0ubuntu3.dsc exaile_0.2.11.1-0ubuntu4.dsc &amp;gt; exaile_0.2.11.1-0ubuntu4.debdiff
&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;Have a look at it, it should include all modifications of previous steps&lt;/p&gt;
&lt;pre class="literal-block"&gt;
diff -Nru exaile-0.2.11.1/debian/changelog exaile-0.2.11.1/debian/changelog
--- exaile-0.2.11.1/debian/changelog        2008-05-27 10:54:56.000000000 -0300
+++ exaile-0.2.11.1/debian/changelog        2008-05-27 10:54:56.000000000 -0300
&amp;#64;&amp;#64; -1,3 +1,11 &amp;#64;&amp;#64;
+exaile (0.2.11.1-0ubuntu4) hardy; urgency=low
+
+  * debian/patches/04_fix_search_exit.dpatch,
+    debian/patches/00list:
+    - Fix clean search terms on exit (LP: #95860)
+
+ -- Mathieu Leplatre &amp;lt;xxxx&amp;#64;gmail.com&amp;gt;  Tue, 27 May 2008 10:45:42 -0300
+
 exaile (0.2.11.1-0ubuntu3) hardy; urgency=low

   * debian/patches/03_fix_mmkeys.dpatch,
diff -Nru /tmp/RIBRnUlXkn/exaile-0.2.11.1/debian/patches/00list /tmp/XQpuhOBOst/exaile-0.2.11.1/debian/patches/00l
ist
--- exaile-0.2.11.1/debian/patches/00list   2008-05-27 10:54:56.000000000 -0300
+++ exaile-0.2.11.1/debian/patches/00list   2008-05-27 10:54:56.000000000 -0300
&amp;#64;&amp;#64; -1,3 +1,5 &amp;#64;&amp;#64;
 01_fix_makefile_for_pysupport
 02_files-on-share-dir
 03_fix_mmkeys
+04_fix_search_exit
+
diff -Nru /tmp/RIBRnUlXkn/exaile-0.2.11.1/debian/patches/04_fix_search_exit.dpatch /tmp/XQpuhOBOst/exaile-0.2.11.1
/debian/patches/04_fix_search_exit.dpatch
--- exaile-0.2.11.1/debian/patches/04_fix_search_exit.dpatch        1969-12-31 21:00:00.000000000 -0300
+++ exaile-0.2.11.1/debian/patches/04_fix_search_exit.dpatch        2008-05-27 10:54:56.000000000 -0300
&amp;#64;&amp;#64; -0,0 +1,27 &amp;#64;&amp;#64;
+#! /bin/sh /usr/share/dpatch/dpatch-run
+## 04_fix_search_exit.dpatch by Mathieu Leplatre &amp;lt;xxxx&amp;#64;gmail.com&amp;gt;
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: Patch to clean search terms on exit
+
+&amp;#64;DPATCH&amp;#64;
+diff -urNad exaile-0.2.11.1~/xl/gui/main.py exaile-0.2.11.1/xl/gui/main.py
+--- exaile-0.2.11.1~/xl/gui/main.py        2007-11-07 13:12:52.000000000 -0300
++++ exaile-0.2.11.1/xl/gui/main.py 2008-05-27 10:37:36.000000000 -0300
+&amp;#64;&amp;#64; -1659,8 +1659,16 &amp;#64;&amp;#64;
+         queuefile = xl.path.get_config('queued.save')
+         if os.path.isfile(queuefile):
+             os.unlink(queuefile)
++
+
+         if self.player.current: self.player.current.stop()
++
++        # Clear the search filter so that the entire playlist is saved
++        self.tracks_filter.set_text('')
++        try:
++            self.on_search()
++        except:  # In case we're quitting before the playlist loaded
++            pass
+
+         for i in range(self.playlists_nb.get_n_pages()):
+             page = self.playlists_nb.get_nth_page(i)
&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
</summary><category term="debian"></category><category term="howto"></category></entry><entry><title>Static build of Cairo and librsvg</title><link href="http://blog.mathieu-leplatre.info/static-build-of-cairo-and-librsvg.html" rel="alternate"></link><updated>2008-07-01T11:25:00+02:00</updated><author><name>Mathieu Leplatre</name></author><id>http://blog.mathieu-leplatre.info/static-build-of-cairo-and-librsvg.html</id><summary type="html">&lt;img alt="images/unicode.png" src="images/unicode.png" /&gt;
&lt;div class="section" id="why"&gt;
&lt;h2&gt;Why ?&lt;/h2&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Convert SVG files to PDF or PNG, with full Unicode support (right-to-left languages), transparency, gradients, PDF image compression, ...&lt;/li&gt;
&lt;li&gt;Cairo and librsvg are the best in town.&lt;/li&gt;
&lt;li&gt;Cairo and librsvg are very modern libraries which became famous only in the past 3 years. Thus, GNU/Linux distributions do not always have recent versions and full capabilities.&lt;/li&gt;
&lt;li&gt;A &lt;cite&gt;static build&lt;/cite&gt; does all the bindings to libraries at compile time, which hence removes specific versions dependencies. &lt;em&gt;(this method has many drawbacks but can help sometimes)&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="the-program-svgconvert-c"&gt;
&lt;h2&gt;The program : svgconvert.c&lt;/h2&gt;
&lt;blockquote&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;This program is a merge of Carl Worth's &lt;a class="reference external" href="http://cgit.freedesktop.org/~cworth/svg2pdf/"&gt;svg2pdf&lt;/a&gt; and &lt;a class="reference external" href="http://cgit.freedesktop.org/~cworth/svg2png/"&gt;svg2png&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="cm"&gt;/*&lt;/span&gt;
&lt;span class="cm"&gt;* Copyright © 2005 Red Hat, Inc.&lt;/span&gt;
&lt;span class="cm"&gt;* Copyright © 2006 Red Hat, Inc.&lt;/span&gt;
&lt;span class="cm"&gt;* Copyright © 2007 Red Hat, Inc.&lt;/span&gt;
&lt;span class="cm"&gt;*&lt;/span&gt;
&lt;span class="cm"&gt;* Permission is hereby granted, free of charge, to any person&lt;/span&gt;
&lt;span class="cm"&gt;* obtaining a copy of this software and associated documentation&lt;/span&gt;
&lt;span class="cm"&gt;* files (the &amp;quot;Software&amp;quot;), to deal in the Software without&lt;/span&gt;
&lt;span class="cm"&gt;* restriction, including without limitation the rights to use, copy,&lt;/span&gt;
&lt;span class="cm"&gt;* modify, merge, publish, distribute, sublicense, and/or sell copies&lt;/span&gt;
&lt;span class="cm"&gt;* of the Software, and to permit persons to whom the Software is&lt;/span&gt;
&lt;span class="cm"&gt;* furnished to do so, subject to the following conditions:&lt;/span&gt;
&lt;span class="cm"&gt;*&lt;/span&gt;
&lt;span class="cm"&gt;* The above copyright notice and this permission notice shall be&lt;/span&gt;
&lt;span class="cm"&gt;* included in all copies or substantial portions of the Software.&lt;/span&gt;
&lt;span class="cm"&gt;*&lt;/span&gt;
&lt;span class="cm"&gt;* THE SOFTWARE IS PROVIDED &amp;quot;AS IS&amp;quot;, WITHOUT WARRANTY OF ANY KIND,&lt;/span&gt;
&lt;span class="cm"&gt;* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF&lt;/span&gt;
&lt;span class="cm"&gt;* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND&lt;/span&gt;
&lt;span class="cm"&gt;* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS&lt;/span&gt;
&lt;span class="cm"&gt;* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN&lt;/span&gt;
&lt;span class="cm"&gt;* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN&lt;/span&gt;
&lt;span class="cm"&gt;* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE&lt;/span&gt;
&lt;span class="cm"&gt;* SOFTWARE.&lt;/span&gt;
&lt;span class="cm"&gt;*&lt;/span&gt;
&lt;span class="cm"&gt;* Authors: Kristian Høgsberg &amp;lt;krh@redhat.com&amp;gt;&lt;/span&gt;
&lt;span class="cm"&gt;* Carl Worth &amp;lt;cworth@redhat.com&amp;gt;&lt;/span&gt;
&lt;span class="cm"&gt;* Behdad Esfahbod &amp;lt;besfahbo@redhat.com&amp;gt;&lt;/span&gt;
&lt;span class="cm"&gt;* Mathieu Leplatre &amp;lt;contact@mathieu-leplatre.info&amp;gt;&lt;/span&gt;
&lt;span class="cm"&gt;*/&lt;/span&gt;

&lt;span class="cp"&gt;#include &amp;lt;stdio.h&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include &amp;lt;stdlib.h&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include &amp;lt;glib/gprintf.h&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include &amp;lt;librsvg/rsvg.h&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include &amp;lt;librsvg/rsvg-cairo.h&amp;gt;&lt;/span&gt;

&lt;span class="cp"&gt;#include &amp;lt;cairo-pdf.h&amp;gt;&lt;/span&gt;

&lt;span class="cp"&gt;#define FAIL(msg) \&lt;/span&gt;
&lt;span class="cp"&gt;do { fprintf (stderr, &amp;quot;FAIL: %s\n&amp;quot;, msg); exit (-1); } while (0)&lt;/span&gt;

&lt;span class="cp"&gt;#define PIXELS_PER_POINT 1&lt;/span&gt;

&lt;span class="cp"&gt;#define PDF 0&lt;/span&gt;
&lt;span class="cp"&gt;#define PNG 1&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;GError&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;RsvgHandle&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;RsvgDimensionData&lt;/span&gt; &lt;span class="n"&gt;dim&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;output_filename&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="n"&gt;cairo_surface_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;surface&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;cairo_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;cr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;cairo_status_t&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argc&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;FAIL&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;usage: svgconvert input_file.svg output_file&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;mode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PDF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g_str_has_suffix&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g_ascii_strdown&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output_filename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;.png&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;mode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PNG&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;g_type_init&lt;/span&gt; &lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="n"&gt;rsvg_set_default_dpi&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;72.0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;handle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rsvg_handle_new_from_file&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;FAIL&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;rsvg_handle_get_dimensions&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;dim&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mode&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;PNG&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;surface&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cairo_image_surface_create&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CAIRO_FORMAT_ARGB32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;surface&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cairo_pdf_surface_create&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output_filename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;cr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cairo_create&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;surface&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;rsvg_handle_render_cairo&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cairo_status&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;FAIL&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cairo_status_to_string&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mode&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;PNG&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;cairo_surface_write_to_png&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;surface&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;output_filename&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;cairo_destroy&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;cairo_surface_destroy&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;surface&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="build-with-shared-librairies"&gt;
&lt;h2&gt;Build with shared librairies&lt;/h2&gt;
&lt;p&gt;You would just do :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;gcc &lt;span class="sb"&gt;`&lt;/span&gt;pkg-config --cflags --libs librsvg-2.0 cairo-pdf&lt;span class="sb"&gt;`&lt;/span&gt; -o svgconvert svgconvert.c
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;which creates a binary of 9.0K.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="build-with-static-librairies"&gt;
&lt;h2&gt;Build with static librairies&lt;/h2&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;First install the development versions of the packages, to make sure you have all &lt;strong&gt;/usr/lib/*.a&lt;/strong&gt; mentioned below.&lt;/li&gt;
&lt;li&gt;Use this Makefile, which creates a binary of 5.9M. It was tested on Ubuntu 8.04 which comes with Gnome 2.22, librsvg 2.22 and Cairo 1.6.0.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nv"&gt;ALL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;svgconvert

&lt;span class="nv"&gt;MYCFLAGS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;pkg-config --cflags librsvg-2.0 cairo-pdf&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;span class="nv"&gt;LDFLAGS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;pkg-config --libs librsvg-2.0 cairo-pdf freetype2 fontconfig pango pangoft2 pangocairo  cairo-ft libthai datrie libgsf-1 gnome-vfs-2.0 libcroco-0.6 libpcre pixman-1 libpng libxml-2.0&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;span class="nv"&gt;MYLDFLAGS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;LDFLAGS&lt;span class="k"&gt;)&lt;/span&gt; /usr/lib/libgio-2.0.a  /usr/lib/libglib-2.0.a /usr/lib/libselinux.a /usr/lib/libexpat.a /usr/lib/libfreetype.a /usr/lib/libbz2.a /usr/lib/libjpeg.a /usr/lib/libtiff.a /usr/lib/libbz2.a /usr/lib/libz.a /usr/lib/libm.a

all: &lt;span class="k"&gt;$(&lt;/span&gt;ALL&lt;span class="k"&gt;)&lt;/span&gt;

%: %.c
    &lt;span class="k"&gt;$(&lt;/span&gt;CC&lt;span class="k"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;$^&lt;/span&gt; -pthread &lt;span class="k"&gt;$(&lt;/span&gt;MYCFLAGS&lt;span class="k"&gt;)&lt;/span&gt; -static &lt;span class="k"&gt;$(&lt;/span&gt;MYLDFLAGS&lt;span class="k"&gt;)&lt;/span&gt; -o &lt;span class="nv"&gt;$@&lt;/span&gt;

clean:
    rm -f &lt;span class="k"&gt;$(&lt;/span&gt;ALL&lt;span class="k"&gt;)&lt;/span&gt; *.o
&lt;/pre&gt;&lt;/div&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;To check if &lt;strong&gt;pkg-config&lt;/strong&gt; knows about a specific library :&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;pkg-config --list-all | grep vfs
gnome-vfs-sharp-2.0           GnomeVfs - GnomeVfs
gnome-vfs-2.0                 gnome-vfs - The GNOME virtual file-system libraries
gnome-vfsmm-2.6               gnome-vfsmm - C++ wrapper &lt;span class="k"&gt;for &lt;/span&gt;gnome-vfs
gnome-vfs-module-2.0          gnome-vfs-module - The GNOME virtual file-system module include info
&lt;/pre&gt;&lt;/div&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;To check if a library has a specific symbol, use the &lt;strong&gt;nm&lt;/strong&gt; command :&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;nm /usr/lib/libexpat.a | grep XML_SetStart
000001c0 T XML_SetStartCdataSectionHandler
00000240 T XML_SetStartDoctypeDeclHandler
00000150 T XML_SetStartElementHandler
000002a0 T XML_SetStartNamespaceDeclHandler
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="download"&gt;
&lt;h2&gt;Download&lt;/h2&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://mathieu-leplatre.info/media/svgconvert-src.tar.gz"&gt;Source&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://mathieu-leplatre.info/media/svgconvert-bin.tar.gz"&gt;Binary&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="references"&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://cairographics.org"&gt;http://cairographics.org&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://librsvg.sourceforge.net"&gt;http://librsvg.sourceforge.net&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Thanks for the precious help of &lt;a class="reference external" href="http://www.cworth.org"&gt;Carl Worth&lt;/a&gt; on &lt;cite&gt;#cairo&lt;/cite&gt; at irc.freenode.net, Zugzwang and nvteighen on &lt;a class="reference external" href="http://ubuntuforums.org"&gt;http://ubuntuforums.org&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
</summary><category term="cairo"></category><category term="svg"></category><category term="C"></category></entry></feed>
