<?xml version="1.0" encoding="UTF-8"?>
<feed
  xmlns="http://www.w3.org/2005/Atom"
  xmlns:thr="http://purl.org/syndication/thread/1.0"
  xml:lang="en"
   >
  <title type="text">Alexandre Bourget</title>
  <subtitle type="text">geek joy</subtitle>

  <updated>2012-01-17T22:15:10Z</updated>
  <generator uri="http://blogofile.com/">Blogofile</generator>

  <link rel="alternate" type="text/html" href="http://blog.abourget.net" />
  <id>http://blog.abourget.net/feed/atom/</id>
  <link rel="self" type="application/atom+xml" href="http://blog.abourget.net/feed/atom/" />
  <entry>
    <author>
      <name>Alexandre Bourget</name>
      <uri>http://blog.abourget.net</uri>
    </author>
    <title type="html"><![CDATA[Job in Montreal, for Python and web lovers]]></title>
    <link rel="alternate" type="text/html" href="http://blog.abourget.net/2011/5/12/job-in-montreal-for-python-and-web-lovers" />
    <id>tag:blog.abourget.net,2011-05-12:0034</id>
    <updated>2011-05-12T15:40:00Z</updated>
    <published>2011-05-12T15:40:00Z</published>
    <category scheme="http://blog.abourget.net" term="Python" />
    <category scheme="http://blog.abourget.net" term="Web development" />
    <summary type="html"><![CDATA[
<div style="float: right; padding-left: 10px; padding-bottom: 10px;">
  <img src="/files/0034/sfl_logo.png" alt="Savoir-faire Linux" />
</div>

<p>Are you a fan of the web ?  Fond of the latest technologies ?  You love Python, and maybe you've tried PHP in the past ?  You're a FLOSS lover and know Linux personally ?  Savoir-faire Linux is the place for you!  Being the Free Software reference in Canada, we're a small and friendly S.M.B. that's growing fast.</p>

<p>We have some great work for you, a great environment, a nice office.  We're located in Montreal, Canada -- a very nice place if you haven't visited yet.</p>

<p>We are a FLOSS service company that offers expertise on a variety of open source / free software products.  We also do some in-house software development and integration of OSS bricks.</p>

<p>We're looking to hire on two fronts: PHP and Python development, both heavily oriented towards the web.</p> 

<p>First, we're looking for some good PHP developers to add to our task force.  We currently have projects running with Drupal and Symfony.</p>

<p>Second, we're seeking talented Python developers, to do some web oriented development, as well as system-level programming and integration.</p>

<p>Candidates must know the HTML/CSS/JS stack thoroughly.  Being in some small and cross-functional teams,  candidates will be called to work on all aspects of web apps (design, usability, integration, back-end programming, database and server-side components integration, etc), depending on the interests and capacities of the team members.  Candidates must be eager to learn a lot of new stuff (our teams like a constant dose of innovation).  We use the Scrum methodology in house and invest a lot in our employees to help them get up to speed with development best practices.</p>

<p>If you're a student, then obviously you don't need to know all these things already, but you should be ready to work hard, on real projects and learn quite a bunch of new things.</p>

<p>Candidates will have opportunities - if desired - to teach what they learn in some of our training classes, to act as consultants at our customers' place, to learn from our support center and infrastructure development team.  We are not a huge company so you won't be a number here.  Work atmosphere is great, the office is cool (even in the summer :), we sometimes can travel for the job, we've got flexible schedules, a social club, we often have "techno-lunches" (midi-technos) to share our knowledge, and there's plenty of good food around (we're located near the Marché Jean-Talon).</p>

<p>For more details, see: <a href="http://www.savoirfairelinux.com">http://www.savoirfairelinux.com</a></p>

<p>We're waiting for your resume here: <a href="mailto:rh@savoirfairelinux.com">rh@savoirfairelinux.com</a> and mention this blog in the body of your message.</p>

<p><b>UPDATE June 7th</b>: corrected typos</p>]]></summary>
  </entry>
  <entry>
    <author>
      <name>Alexandre Bourget</name>
      <uri>http://blog.abourget.net</uri>
    </author>
    <title type="html"><![CDATA[New and hot, part 1: Meta presentation]]></title>
    <link rel="alternate" type="text/html" href="http://blog.abourget.net/2011/4/01/new-and-hot-part-1-meta-presentation" />
    <id>tag:blog.abourget.net,2011-04-01:0024</id>
    <updated>2011-04-01T09:50:00Z</updated>
    <published>2011-04-01T09:50:00Z</published>
    <category scheme="http://blog.abourget.net" term="Python" />
    <category scheme="http://blog.abourget.net" term="Web development" />
    <summary type="html"><![CDATA[

<p>This is part 1 of my <a href="http://confoo.ca/en/2011/session/the-pylons-project-new-and-hot-stuff-live-demo">March 9th 2011 Confoo presentation</a>.  Refer to the <a href="/2011/3/09/new-and-hot-stuff-in-the-pylons-project/">Table of Contents</a> for the other parts.</p>

<p>This is a meta-presentation.  It's a presentation of the tools and things I've used to build and perform the actual presentation I gave.  It is not directly related to Pyramid or Python.</p>

<h3>Presentation of my setup and the tools used.</h3>

<p>Some people come to me and express wonder on the flow of my live presentation, because it all seems to just work all the time, even without Internet access.  Here is what I've done to make things look like they actually work:</p>

<h4>Scripts to handle different tasks with keyboard shortcuts</h4>

<p>Here is a script I've written that lists a bunch of events with associated chunks of code to be executed when I launch them.  The script allows me to hit <code>Ctrl+Spacebar</code> and type in a couple of letters, and then launches the associated piece of code.</p>

<p>They require the Ubuntu <code>xclip</code> and <code>beep</code> packages to be installed. The scripts are available here:</p>

<p><a href="/files/foopres/apps.py">apps.py</a>, <a href="/files/foopres/gtkdrive.glade">gtkdrive.glade</a>, <a href="/files/foopres/gtkdrive.py">gtkdrive.py</a>, <a href="/files/foopres/mod_confoo2011.py">mod_confoo2011.py</a>, <a href="/files/foopres/presmod.py">presmod.py</a></p>

<p>This required <a href="http://www.howtogeek.com/howto/ubuntu/assign-custom-shortcut-keys-on-ubuntu-linux/">setting some global hotkeys</a> like this:</p>


<div class="pygments_tango"><pre><span class="nv">$ </span><span class="c"># Support for compiz (use `ccsm` to activate the &quot;Commands&quot; plugin)</span>
<span class="nv">$ </span>gconftool-2 --type string --set /apps/compiz/plugins/commands/command0 <span class="s2">&quot;echo 1 &gt; /tmp/btntrigger&quot;</span>
<span class="nv">$ </span>gconftool-2 --type string --set /apps/compiz/plugins/commands/run_command0_key <span class="s2">&quot;&lt;Super&gt;space&quot;</span>
<span class="nv">$ </span><span class="c"># Support for metacity:</span>
<span class="nv">$ </span>gconftool-2 --type string --set /apps/metacity/keybinding_commands/command_1 <span class="s2">&quot;echo 1 &gt; /tmp/btntrigger&quot;</span> 
<span class="nv">$ </span>gconftool-2 --type string --set /apps/metacity/global_keybindings/run_command_1 <span class="s2">&quot;&lt;Super&gt;space&quot;</span>
</pre></div>




<p>Afterwards, hitting <code>&lt;Super&gt;space</code> will pop up a little window like this:</p>

<div style="text-align: center;"><img src="/files/0024/littlebox.png" alt="Little box" /></div>

<p>In there, typing one of the commands that were listed when running the presentation will run the associated method in <code>mod_confoo2011.py</code>.</p>


<h4>Emacs tweaks</h4>

<p>I've added this snippet of code to my <code>~/.emacs</code> file to adjust the font size, making sure people can see something from a distance and fits a 1024x768 resolution at 80 characters wide (<a href="http://stackoverflow.com/questions/294664/how-to-set-the-font-size-in-emacs">grabbed here</a>):</p>


<div class="pygments_tango"><pre>;; When doing a presentation:
(set-face-attribute &#39;default nil :height 150)
</pre></div>





<p>Also to speed up things when dealing with boilerplate, I'm using <a href="http://code.google.com/p/yasnippet/">yasnippet</a> for Emacs</p>


<div class="pygments_tango"><pre>;; .emacs
(add-to-list &#39;load-path &quot;~/.emacs.d/plugins/yasnippet-0.6.1c&quot;)
(require &#39;yasnippet)
(yas/initialize)
(yas/load-directory &quot;~/.emacs.d/snippets&quot;)
</pre></div>




<p>and <a href="/files/foopres/yasnippets">these yasnippets</a> in my <code>~/.emacs.d/snippets</code> directory.  You'll find in there only the ones I actually used in the presentation, and not the standard ones.</p>


<h4>Bash shortcuts</h4>

<p>I've added a couple of aliases to speed things up in the presentation.  Here is a list of what I've used:</p>


<div class="pygments_tango"><pre><span class="c"># To use throughout the code to refer to my custom-built FFmpeg. See the post on FFmpeg</span>
<span class="nb">export </span><span class="nv">FFMPEG</span><span class="o">=</span>/home/abourget/build/ffmpeg-0.6.1/bin/ffmpeg

<span class="c"># To make sure I load ipython using the local virtualenv</span>
<span class="nb">alias </span><span class="nv">ipython</span><span class="o">=</span><span class="s2">&quot;python `which ipython`&quot;</span>

<span class="c"># PIP download cache, don&#39;t download things twice.</span>
<span class="nb">export </span><span class="nv">PIP_DOWNLOAD_CACHE</span><span class="o">=</span>~/.pip/download_cache
</pre></div>




<p>Using PIP_DOWNLOAD_CACHE allowed me to install things more quickly.  If I had downloaded the package already, it would take it from my download cache.  This doesn't prevent *all* Internet access, as <code>pip</code> will still go look on the PyPI if it's the latest version for example.</p>

<p>You could also have set up a local mirror with the packages you needed, and install everything following <a href="http://jacobian.org/writing/when-pypi-goes-down/">this method</a>.</p>

<h4>Squid caching proxy</h4>

<p>At first, I wanted to use Squid caching to fake I had an Internet connection, but in the end, the presentation room did have Internet and I had a cell phone with tethering enabled so I didn't need the proxy.  But still, here is how I did it the year before:</p>

<pre>
$ sudo apt-get install squid3
</pre>

<p>Tweak the squid3 proxy config:<p>

<pre>
# Add:
refresh_pattern .               1440    90%     4320 reload-into-ims ignore-no-cache ignore-reload override-expire
# Comment out:
#refresh_pattern -i (/cgi-bin/|\?) 0    0%      0    
# Enable:
offline_mode on
</pre>

<p>Restart the server, and you should be all set. In any console you wish to use the proxy, run:</p>

<pre>
$ export http_proxy=http://localhost:3128
</pre>


<h4>Pre-fetched downloads</h4>

<p>I've downloaded the HTML5 boilerplate code from <a href="http://html5boilerplate.com/">http://html5boilerplate.com/</a>.</p>

<p>I also had a copy of <code>socket.io.js</code> from <a href="http://cdn.socket.io/stable/socket.io.js">here</a>.</p>


<h4>Video and sound recordings</h4>

<p>To do video recording of the screen, I've used this <code>ffmpeg</code> command:</p>

<pre>
~/build/ffmpeg-0.6.1/bin/ffmpeg -y -f x11grab -r 12 -s 1024x768 -i :0.0 -vcodec libx264 -vpre veryfast Presentation.mkv
</pre>

<p>Sound recording was made with an old SIM-less HTC Dream (USA's G1), running a free Android application named <a href="http://www.appbrain.com/app/virtual-recorder/ix.com.android.VirtualRecorder">Virtual Recorder</a>, recording in PCM WAVE using the microphone-earbuds thing that came with the phone.</p>


<h4>Someone to tape the presentation, using an external camcorder.</h4>

<p>I was using a SANYO Xacti camera, which spat some already-encoded H.264/AVC, that was sitting on a tripod.</p>


<h4>Final rendering</h4>

<p>The final rendering was done with Cinelerra, using ReframeRT to adjust the frame-rate of the Presentation.mkv file, produced by FFmpeg's x11grab.  I also needed to adjust the frame-rate for some reasons</p>

<p>I used the audio from the Android device, the video from tx11grab

<h4>YouTube publishing</h4>

<p>I've used YouTube to publish the video parts, and this <a href="">Blogofile</a> blog for the tutorials themselves.  Here is the YouTube result:</p>

<div class="video" style="text-align: center;">
  <object width="480" height="385"><param name="movie" value="http://www.youtube.com/p/1AA86FF9B5E5C551?hl=fr_FR&fs=1"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/p/1AA86FF9B5E5C551?hl=fr_FR&fs=1" type="application/x-shockwave-flash" width="480" height="385" allowscriptaccess="always" allowfullscreen="true"></embed></object>
</div>


<!--

 SETUP for presentation:
  - Load the http://html5boilerplate.com/ website in browser somewhere.
  - Load the http://docs.pylonshq.com/pyramid/dev/ docs page somewhere.
  - Load http://socket.io/ to show off..
  - Setup video recording with:
    ~/build/ffmpeg-0.6.1/bin/ffmpeg -y -f x11grab -r 12 -s 1024x768 -i :0.0 -vcodec libx264 -vpre veryfast Presentation.mkv

    - For audio, add: -f alsa -ac 2 -i pulse  -acodec pcm_s16le
      Or: -acodec libvorbis -ab 128k -ac 2
    - See also: http://ubuntuforums.org/showthread.php?t=1392026
  - Make sure $FFMPEG is pointing to the location of the good build (tweak .bashrc)
  - Make sure we have a patched version of paste.fileapp for DataApp to support GridOut
  - Run "blogofile build" and "blogofile serve" in the background.  http://localhost:8080 with my posts.
  - "modprobe pcspkr" for the beeps to happen, when using "foopres". (make sure 'beep' is installed)
  - Open "gqview" and go to settings, make sure it opens images in stretched full-screen mode.. so you don't need to zoom in my hand


 NOTES on presentation:
  - Each time I type something in, I should WAIT for a couple of seconds for
    people to understand what I just typed in.
  - For each question asked, I must repeat the question for the microphone to
    catch up.
  - At the end, write a good .gitignore in the ~/Foo dir, and publish the whole output to github with links to the presentation on my blog.

 REQUIRED for presentation:
  - Screen recording working at 1024x768 (look into mjpeg, mpng for lossless)
  - Someone filming from the outside
  - 

-->


]]></summary>
  </entry>
  <entry>
    <author>
      <name>Alexandre Bourget</name>
      <uri>http://blog.abourget.net</uri>
    </author>
    <title type="html"><![CDATA[New and hot, part 6: Redis, Publish and Subscribe]]></title>
    <link rel="alternate" type="text/html" href="http://blog.abourget.net/2011/3/31/new-and-hot-part-6-redis-publish-and-subscribe" />
    <id>tag:blog.abourget.net,2011-03-31:0031</id>
    <updated>2011-04-01T11:28:00Z</updated>
    <published>2011-03-31T16:40:00Z</published>
    <category scheme="http://blog.abourget.net" term="Python" />
    <category scheme="http://blog.abourget.net" term="Web development" />
    <summary type="html"><![CDATA[

<p>This is part 6 of my <a href="http://confoo.ca/en/2011/session/the-pylons-project-new-and-hot-stuff-live-demo">March 9th 2011 Confoo presentation</a>.  Refer to the <a href="/2011/3/09/new-and-hot-stuff-in-the-pylons-project/">Table of Contents</a> for the other parts.</p>

<p>The original announcement for my Confoo presentation was to <a href="">use RabbitMQ to do real-time communications</a>, but then, after finding a way to use Redis to do it, I found it was simpler and more straight-forward for a live demo.</p>

<div style="text-align: center;"><iframe title="YouTube video player" width="480" height="390" src="http://www.youtube.com/embed/hrpO2pzzMUE" frameborder="0" allowfullscreen></iframe><br />
<span><a href="http://www.youtube.com/watch?v=hrpO2pzzMUE">Video of the Confoo conference, March 9th 2011.</a></span></div>

<h3>Redis Integration</h3>

<p>In this part, we will use Redis's PubSub features to communicate in real-time between the different web browsers connected with a Socket.IO (or a Websocket) to our Gevent-based application.</p>

<p>Redis is a FOSS database which supports the Publish/Subscribe metaphore. It is written in C, and is quite robust.  It also comes pre-setup on your Ubuntu machine.</p>

<div class="fooevent"><span>redis</span> Show the install instructions for redis-server.</div>

<p>To install Redis, simply run:</p>


<div class="pygments_tango"><pre><span class="nv">$ </span>sudo apt-get install redis-server
</pre></div>




<p>and you're ready to go!  To get things into production, you'll want to learn how to secure your installation.</p>

<p>You can try the redis server locally if you kill the system-wide instance (through init.d/service scripts):</p>


<div class="pygments_tango"><pre><span class="nv">$ </span>redis-server
...
<span class="o">[</span>21194<span class="o">]</span> 08 Mar 22:08:54 * Server started, Redis version 1.3.15
...
<span class="o">[</span>21194<span class="o">]</span> 08 Mar 22:08:54 * The server is now ready to accept connections on port 6379
<span class="o">[</span>21194<span class="o">]</span> 08 Mar 22:08:54 - 0 clients connected <span class="o">(</span>0 slaves<span class="o">)</span>, 533436 bytes in use
</pre></div>





<h3>Python Redis bindings and PubSub commands</h3>

<p>Let's setup what is needed for messaging using Redis.</p>

<p>First of all, we'll want to connect to the Redis server and publish a new message.  We'll add some code to the <code>views.py</code> and set up the publisher.  We'll name the channel <em>foo</em>:</p>


<div class="pygments_tango"><pre><span class="o">...</span>
<span class="kn">import</span> <span class="nn">redis</span>
<span class="kn">from</span> <span class="nn">json</span> <span class="kn">import</span> <span class="n">loads</span><span class="p">,</span> <span class="n">dumps</span>
<span class="o">...</span>
<span class="k">def</span> <span class="nf">encode_video</span><span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="n">request</span><span class="p">):</span>
    <span class="o">...</span>
    <span class="k">if</span> <span class="n">p</span><span class="o">.</span><span class="n">returncode</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
        <span class="n">r</span> <span class="o">=</span> <span class="n">redis</span><span class="o">.</span><span class="n">Redis</span><span class="p">()</span>
        <span class="n">msg</span> <span class="o">=</span> <span class="p">{</span><span class="s">&#39;type&#39;</span><span class="p">:</span> <span class="s">&#39;video&#39;</span><span class="p">,</span> <span class="s">&#39;fileid&#39;</span><span class="p">:</span> <span class="nb">str</span><span class="p">(</span><span class="n">fileid</span><span class="p">),</span>
               <span class="s">&#39;url&#39;</span><span class="p">:</span> <span class="n">request</span><span class="o">.</span><span class="n">route_url</span><span class="p">(</span><span class="s">&#39;video&#39;</span><span class="p">,</span> <span class="n">fileid</span><span class="o">=</span><span class="n">fileid</span><span class="p">)}</span>
        <span class="n">r</span><span class="o">.</span><span class="n">publish</span><span class="p">(</span><span class="s">&quot;foo&quot;</span><span class="p">,</span> <span class="n">dumps</span><span class="p">(</span><span class="n">msg</span><span class="p">))</span>
</pre></div>




<p>Now, we'll want to have our Socket.IO socket listen for any incoming message from the Redis subscription:</p>


<div class="pygments_tango"><pre><span class="k">class</span> <span class="nc">ConnectIOContext</span><span class="p">(</span><span class="n">SocketIOContext</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">msg_connect</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">msg</span><span class="p">):</span>
        <span class="o">...</span>
        <span class="k">def</span> <span class="nf">listener</span><span class="p">():</span>
            <span class="n">r</span> <span class="o">=</span> <span class="n">redis</span><span class="o">.</span><span class="n">Redis</span><span class="p">()</span>
            <span class="n">r</span><span class="o">.</span><span class="n">subscribe</span><span class="p">([</span><span class="s">&#39;foo&#39;</span><span class="p">])</span>
            <span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="n">r</span><span class="o">.</span><span class="n">listen</span><span class="p">():</span>
                <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">io</span><span class="o">.</span><span class="n">connected</span><span class="p">():</span>
                    <span class="k">return</span>
                <span class="k">print</span> <span class="s">&quot;From Redis:&quot;</span><span class="p">,</span> <span class="n">m</span>
                <span class="k">if</span> <span class="n">m</span><span class="p">[</span><span class="s">&#39;type&#39;</span><span class="p">]</span> <span class="o">==</span> <span class="s">&#39;message&#39;</span><span class="p">:</span>
                    <span class="bp">self</span><span class="o">.</span><span class="n">io</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">loads</span><span class="p">(</span><span class="n">m</span><span class="p">[</span><span class="s">&#39;data&#39;</span><span class="p">]))</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">spawn</span><span class="p">(</span><span class="n">listener</span><span class="p">)</span>
</pre></div>




<p>When we receive a message as the <code>m</code> object, we'll just pass it directly to the current Socket.IO socket.  We've subscribed to the <code>foo</code> channel, so we'll receive a copy of any message sent to it.</p>

<p>We will also want the client to handle the new message, so we'll tweak the call to <code>go()</code> and the definition for the <code>go()</code> function, in <code>index.html</code>:</p>


<div class="pygments_tango"><pre>      <span class="o">&lt;</span><span class="nx">script</span><span class="o">&gt;</span>
        <span class="kd">function</span> <span class="nx">go</span><span class="p">(</span><span class="nx">url</span><span class="p">)</span> <span class="p">{</span>
          <span class="nx">$</span><span class="p">(</span><span class="s1">&#39;#video&#39;</span><span class="p">).</span><span class="nx">html</span><span class="p">(</span><span class="s1">&#39;&lt;div&gt;Video ready: &#39;</span> <span class="o">+</span> <span class="nx">url</span> <span class="o">+</span> <span class="s1">&#39;&lt;/div&gt;&lt;video controls preload src=&quot;&#39;</span><span class="o">+</span> <span class="nx">url</span> <span class="o">+</span> <span class="s1">&#39;&quot; /&gt;&#39;</span><span class="p">);</span>
          <span class="p">...</span>
        <span class="p">}</span>
      <span class="o">&lt;</span><span class="err">/script&gt;</span>

      <span class="p">...</span>
      <span class="nx">socket</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">&#39;message&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">obj</span><span class="p">)</span> <span class="p">{</span>
        <span class="p">...</span>
        <span class="k">if</span> <span class="p">(</span><span class="nx">obj</span><span class="p">.</span><span class="nx">type</span> <span class="o">==</span> <span class="s2">&quot;video&quot;</span><span class="p">)</span> <span class="p">{</span>
          <span class="nx">go</span><span class="p">(</span><span class="nx">obj</span><span class="p">.</span><span class="nx">url</span><span class="p">);</span>
        <span class="p">}</span>
        <span class="p">...</span>
</pre></div>




<p>In here, if the message is of type <code>video</code>, like the one sent by the <code>encode_video()</code> function, it will trigger the playback immediately.</p>

<p>Let's make sure a background process is spawned when someone asks us to encode a video.  The encoding process itself could be totally decoupled from this server, sent to a render farm for example.  In <code>views.py</code>, we would tweak:</p>


<div class="pygments_tango"><pre><span class="k">def</span> <span class="nf">get_iframe</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
    <span class="k">if</span> <span class="s">&#39;file&#39;</span> <span class="ow">in</span> <span class="n">request</span><span class="o">.</span><span class="n">params</span><span class="p">:</span>
        <span class="o">...</span>
        <span class="n">gevent</span><span class="o">.</span><span class="n">spawn</span><span class="p">(</span><span class="n">encode_video</span><span class="p">,</span> <span class="s">&#39;/tmp/video.mp4&#39;</span><span class="p">,</span> <span class="n">request</span><span class="p">)</span>
</pre></div>




<p>That's it! Hope you liked the series!  I might add the Android app demo if I have time, so please be patient.</p>

<p>If you would like us to implement anything you've seen here in a real-life project, or to kick start some of your projects, don't hesitate to send out an e-mail at <a href="mailto:contact@savoirfairelinux.com">contact@savoirfairelinux.com</a> and mention this blog.</p>
]]></summary>
  </entry>
  <entry>
    <author>
      <name>Alexandre Bourget</name>
      <uri>http://blog.abourget.net</uri>
    </author>
    <title type="html"><![CDATA[New and hot, part 5: MongoDB integration]]></title>
    <link rel="alternate" type="text/html" href="http://blog.abourget.net/2011/3/23/new-and-hot-part-5-mongodb-integration" />
    <id>tag:blog.abourget.net,2011-03-23:0029</id>
    <updated>2011-03-31T16:56:00Z</updated>
    <published>2011-03-23T13:32:00Z</published>
    <category scheme="http://blog.abourget.net" term="Python" />
    <category scheme="http://blog.abourget.net" term="Web development" />
    <summary type="html"><![CDATA[

<p>This is part 5 of my <a href="http://confoo.ca/en/2011/session/the-pylons-project-new-and-hot-stuff-live-demo">March 9th 2011 Confoo presentation</a>.  Refer to the <a href="/2011/3/09/new-and-hot-stuff-in-the-pylons-project/">Table of Contents</a> for the other parts.</p>

<div style="text-align: center;"><iframe title="YouTube video player" width="480" height="390" src="http://www.youtube.com/embed/hHiGJvdPZW8" frameborder="0" allowfullscreen></iframe><br />
<span><a href="http://www.youtube.com/watch?v=hHiGJvdPZW8">Video of the Confoo conference, March 9th 2011.</a></span></div>

<h3>MongoDB integration</h3>

<p>In this part, we will make our system scale, by using a distributed file system to store our encoded files.  We will be using GridFS that is backed by MongoDB, which can be sharded and replicated to scale.</p>

<p>First off, let's install MongoDB.  You can get <a href="http://www.mongodb.org/display/DOCS/Ubuntu+and+Debian+packages">Ubuntu installation instructions here</a>.</p>

<div class="fooevent"><span>mongoinstall</span> Display the install instructions on screen.</div>


<div class="pygments_tango"><pre>$ sudo -s
# echo &quot;deb http://downloads.mongodb.org/distros/ubuntu 10.10 10gen&quot; &gt; /etc/apt/sources.list.d/mongodb.list
# apt-key adv --keyserver keyserver.ubuntu.com --recv 7F0CEB10
# apt-get update
# apt-get install mongodb-stable
</pre></div>




<p>We will create a local MongoDB data dir, and we'll run the server as a normal user:</p>


<div class="pygments_tango"><pre><span class="nv">$ </span>mkdir mongodata
</pre></div>




<p>To launch MongoDB on the default port, as a normal user:</p>


<div class="pygments_tango"><pre><span class="nv">$ </span>mongod --dbpath ./mongodata
</pre></div>




<p>Back to Pyramid, most of the database-related elments will go in <code>resources.py</code> in a Pyramid project.  This is where we'll add our code to handle the connections to MongoDB:</p>


<div class="pygments_tango"><pre><span class="c">## resources.py</span>
<span class="o">...</span>

<span class="kn">from</span> <span class="nn">gridfs</span> <span class="kn">import</span> <span class="n">GridFS</span>
<span class="kn">import</span> <span class="nn">pymongo</span>

<span class="n">mongo_conn</span> <span class="o">=</span> <span class="n">pymongo</span><span class="o">.</span><span class="n">Connection</span><span class="p">()</span>

<span class="k">def</span> <span class="nf">add_mongo</span><span class="p">(</span><span class="n">event</span><span class="p">):</span>
    <span class="n">req</span> <span class="o">=</span> <span class="n">event</span><span class="o">.</span><span class="n">request</span>
    <span class="n">req</span><span class="o">.</span><span class="n">db</span> <span class="o">=</span> <span class="n">mongo_conn</span><span class="p">[</span><span class="s">&#39;testdb&#39;</span><span class="p">]</span>
    <span class="n">req</span><span class="o">.</span><span class="n">fs</span> <span class="o">=</span> <span class="n">GridFS</span><span class="p">(</span><span class="n">req</span><span class="o">.</span><span class="n">db</span><span class="p">)</span>
</pre></div>




<p>We import <code>GridFS</code>, the filesystem handler, and <code>pymongo</code>, which is the low-level mongodb library.  We keep a reference to a connection in <code>mongo_conn</code>.  This connection object will be pooled, so when we get a reference to a particular database, it takes a connection from the pool and returns it upon deletion.</p>

<p>The <code>add_mongo()</code> function that is defined here will be hooked to be executed for each new request.  This way, we will have a <code>db</code> and an <code>fs</code> attribute on each request going through our app.  To do so, we'll modify <code>__init__.py</code> this way:</p>    


<div class="pygments_tango"><pre><span class="k">def</span> <span class="nf">main</span><span class="p">(</span><span class="o">...</span><span class="p">):</span>
    <span class="o">...</span>
    <span class="n">config</span><span class="o">.</span><span class="n">add_subscriber</span><span class="p">(</span><span class="s">&#39;foo.resources.add_mongo&#39;</span><span class="p">,</span>
                          <span class="s">&#39;pyramid.events.NewRequest&#39;</span><span class="p">)</span>
    <span class="o">...</span>
</pre></div>




<p>And then we're set for database.</p>

<h3>GridFS: Using MongoDB as a filestore</h3>

<p>Here we will store our compressed video files into the distributed filesystem MongoDB provides.  GridFS is backed by MongoDB's features (document-oriented database for metadata) and has elegant python bindings.</p>

<p>If we store videos in MongoDB, we'll want to be able to retrieve them from there as well, so we will need to tweak the route to get them. In <code>__init__.py</code>:</p>


<div class="pygments_tango"><pre><span class="k">def</span> <span class="nf">main</span><span class="p">(</span><span class="o">...</span><span class="p">):</span>
    <span class="o">...</span>
    <span class="n">config</span><span class="o">.</span><span class="n">add_route</span><span class="p">(</span><span class="s">&#39;video&#39;</span><span class="p">,</span> <span class="s">&#39;video/{fileid}.webm&#39;</span><span class="p">)</span>
    <span class="o">...</span>
</pre></div>




<p>See that <code>fileid</code> ?  We'll get it in the view filled with what matched in the requested URL.</p>

<p>Then, we'll modify the encoding process to dump the output directly to MongoDB, using Python's pipes:</p>


<div class="pygments_tango"><pre><span class="k">def</span> <span class="nf">encode_video</span><span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="n">request</span><span class="p">):</span>
    <span class="n">p</span> <span class="o">=</span> <span class="n">subprocess</span><span class="o">.</span><span class="n">Popen</span><span class="p">(</span><span class="s">&#39;$FFMPEG -y -i </span><span class="si">%s</span><span class="s"> ... -ac 2 -&#39;</span> <span class="o">%</span> <span class="n">filename</span><span class="p">,</span>
                         <span class="n">shell</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">stdout</span><span class="o">=</span><span class="n">subprocess</span><span class="o">.</span><span class="n">PIPE</span><span class="p">)</span>
    <span class="n">stdout</span><span class="p">,</span> <span class="n">stderr</span> <span class="o">=</span> <span class="n">p</span><span class="o">.</span><span class="n">communicate</span><span class="p">()</span>
    <span class="n">fileid</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">fs</span><span class="o">.</span><span class="n">put</span><span class="p">(</span><span class="n">stdout</span><span class="p">,</span> <span class="n">content_type</span><span class="o">=</span><span class="s">&quot;video/webm&quot;</span><span class="p">,</span>
                            <span class="n">original_user</span><span class="o">=</span><span class="s">&quot;123&quot;</span><span class="p">)</span>
    <span class="k">print</span> <span class="s">&quot;Video URL: &quot;</span><span class="p">,</span> <span class="n">request</span><span class="o">.</span><span class="n">route_url</span><span class="p">(</span><span class="s">&#39;video&#39;</span><span class="p">,</span> <span class="n">fileid</span><span class="o">=</span><span class="n">fileid</span><span class="p">)</span>
</pre></div>




<p>What's to note here is the addition of the <code>request</code> parameter in the <code>encode_video()</code> call.  This will allow us to create a URL with <code>route_url()</code>.  Also we changed the <em>output</em> for FFmpeg, not pointing to <code>/tmp/output.webm</code> anymore, but to <em>stdout</em> using a dash.  We've added <code>stdout=subprocess.PIPE</code> also, to get a hand of the output.</p>

<p>The <code>request.fs.put()</code> method will create a new file in the <code>GridFS</code> attached to <code>request.fs</code> and takes FFmpeg's <code>stdout</code> as a file-like object to fetch content from (as it's stdin).  The end result is a new file in the distribute file system.  <code>put()</code> takes any keyword arguments, and will add that meta-data to the <em>fs.files</em> collection's document objects. That's why <code>original_user="123"</code> can be added, and searched for later on.</p>

<p>Then, we'll make sure we fetch the data from MongoDB when a web request comes in for a video:</p>

<div class="fooevent"><span>objectid</span> YASnippet to add the import statements.</div>
<div class="fooevent"><span>dataapp</span> YASnippet to add the WSGIAPP line.</div>


<div class="pygments_tango"><pre><span class="kn">from</span> <span class="nn">pymongo.objectid</span> <span class="kn">import</span> <span class="n">ObjectId</span>
<span class="kn">from</span> <span class="nn">paste.fileapp</span> <span class="kn">import</span> <span class="n">DataApp</span>

<span class="nd">@view_config</span><span class="p">(</span><span class="n">route_name</span><span class="o">=</span><span class="s">&quot;get_video&quot;</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">get_video</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
    <span class="n">oid</span> <span class="o">=</span> <span class="n">ObjectId</span><span class="p">(</span><span class="n">request</span><span class="o">.</span><span class="n">matchdict</span><span class="p">[</span><span class="s">&#39;fileid&#39;</span><span class="p">])</span>
    <span class="n">filein</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">fs</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">oid</span><span class="p">)</span>
    <span class="n">wsgiapp</span> <span class="o">=</span> <span class="n">DataApp</span><span class="p">(</span><span class="n">filein</span><span class="p">,</span> <span class="n">headers</span><span class="o">=</span><span class="p">[(</span><span class="s">&quot;Content-Type&quot;</span><span class="p">,</span> <span class="s">&quot;video/webm&quot;</span><span class="p">)],</span>
                      <span class="n">filelike</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">request</span><span class="o">.</span><span class="n">get_response</span><span class="p">(</span><span class="n">wsgiapp</span><span class="p">)</span>
</pre></div>




<p>(Note that we need a <a href="/files/0029/fileapp.patch">patched paste.fileapp.DataApp</a> for this to work.)</p>

<p>This chunk will get the <code>fileid</code> from the URL, make it an <code>ObjectId</code> and query the GridFS instance with <code>request.fs.get(oid)</code>.  This will return a file-like object that we'll pass to <code>DataApp</code>, which is a simple file-serving mechanisms that deals with Byte-Ranges and ETags and those kind of things.</p>

<p>To try it out, upload a video, and find the link in the server's stdout and load it in your browser (or mplayer).  If it plays correctly, then it works!</p>

<p>Next will be Redis integration with its PubSub support, so that when the video is ready, it's pushed directly to all web viewers.</p>

<p>If you would like us to implement anything you've seen here in a real-life project, or to kick start some of your projects, don't hesitate to send out an e-mail at <a href="mailto:contact@savoirfairelinux.com">contact@savoirfairelinux.com</a> mentioning this blog.</p>
]]></summary>
  </entry>
  <entry>
    <author>
      <name>Alexandre Bourget</name>
      <uri>http://blog.abourget.net</uri>
    </author>
    <title type="html"><![CDATA[New and hot, part 4: Pyramid, Socket.IO and Gevent]]></title>
    <link rel="alternate" type="text/html" href="http://blog.abourget.net/2011/3/17/new-and-hot-part-4-pyramid-socket-io-gevent" />
    <id>tag:blog.abourget.net,2011-03-17:0027</id>
    <updated>2011-03-17T12:10:00Z</updated>
    <published>2011-03-17T12:10:00Z</published>
    <category scheme="http://blog.abourget.net" term="Python" />
    <category scheme="http://blog.abourget.net" term="Web development" />
    <summary type="html"><![CDATA[

<p>This is part 4 of my <a href="http://confoo.ca/en/2011/session/the-pylons-project-new-and-hot-stuff-live-demo">March 9th 2011 Confoo presentation</a>.  Refer to the <a href="/2011/3/09/new-and-hot-stuff-in-the-pylons-project/">Table of Contents</a> for the other parts.</p>

<h3>Gevent</h3>

<p>In this section, we will change HTTP server from paster's to <a href="http://www.gevent.org/">Gevent</a>'s.  We will also implement Socket.IO in our Pyramid application and have the client communicate in full duplex with the server.  We will then graph the CPU usage (on a Linux machine) directly to the web viewer.</p>

<p>Gevent is a micro-threading library (à la Stackless Python) and it's HTTP server supports a large number of concurrent connections, which yield an event when new data is available. It is based on <a href="http://monkey.org/~provos/libevent/">libevent</a> and Python's <a href="http://packages.python.org/greenlet/">greenlet</a>s.</p>

<div class="fooevent"><span>gevent</span> Show the install instructions for gevent and pyramid_socketio.</div>

<p>Requirements for Gevent:</p>


<div class="pygments_tango"><pre><span class="o">(</span>env<span class="o">)</span><span class="nv">$ </span>sudo apt-get install libevent-dev
<span class="o">(</span>env<span class="o">)</span><span class="nv">$ </span>pip install gevent gevent-websocket gevent-socketio
</pre></div>




<p>This will also installs <code>greenlet</code>, on which it is based.</p>


<h3>Pyramid's Socket.IO integration layer</h3>

<p>We'll install the <code>pyramid_socketio</code> package, that will tie in all the Socket.IO support, and allow us to write beautiful stateful classes for each client.</p>


<div class="pygments_tango"><pre><span class="o">(</span>env<span class="o">)</span><span class="nv">$ </span>pip install pyramid_socketio
</pre></div>




<p>This package will bring in it's dependencies: <code>gevent-websocket, gevent-socketio, gevent</code> and <code>greenlet</code>.

<p><code>gevent-websocket</code> gives us WebSocket support and implements the WebSocket protocol on top of Gevent.  It is used by <code>gevent-socketio</code> when dealing with WebSocket, otherwise, Socket.IO's fallbacks are handled directly.</p>


<h3>Switching from Paster to Gevent's server</h3>

<p>Thankfully, <code>pyramid_socketio</code> provides with a simple script to replace our call to <code>paster serve --reload file.ini</code> or <code>paster serve file.ini</code>.  It's <code>socketio-serve-reload file.ini</code> and <code>socketio-serve file.ini</code>, respectively.</p>



<div class="pygments_tango"><pre><span class="o">(</span>env<span class="o">)</span><span class="nv">$ </span>paster serve --reload development.ini
...
^C^C caught in monitor process
<span class="o">(</span>Killed<span class="o">)</span>
<span class="o">(</span>env<span class="o">)</span><span class="nv">$ </span>socketio-serve-reload development.ini
...
</pre></div>




<p>The Socket.IO server handles the initialization of the <code>logging</code> library, the setup of a watcher if you ask for code reloading, will read host/port from your .ini file, just like paster did, it will attempt to listen on port 843 (must be run as root though) to setup the Flash Socket Policy server, if you want to use the Flash WebSocket fallback.  Otherwise, it's a drop-in replacement for <code>paster serve</code>.</p>

<p>When using the <code>socketio-serve</code> server, Gevent will automatically be initialized and will monkey patch several modules (like <code>socket</code> and <code>threading</code>) to make sure it has versions that will yield control to Gevent instead of blocking on I/O.  From that point on, any process that would start off a new thread will, without knowing it, launch a new Greenlet, using the same APIs, transparently.</p>

<p>Also, if you want <code>subprocess</code> support in your application (which we will need), get <a href="http://gevent.googlegroups.com/attach/a16b89925a937076/subprocess.py?part=4">this version</a>, by a guy who ported the stdlib subprocess to handle gevent's event loop, and never block on I/O.</p>

<div class="fooevent"><span>subprocess</span> Copy the vendor/subprocess.py file from the web location above, in the ~/Foo/foo directory.. for use within views.py</div>



 
<h3>Quick look at the code</h3>

<p>Let's have a quick look of how Gevent works, from a stripped-down version of the <code>socketio-serve</code> script:</p>


<div class="pygments_tango"><pre><span class="c"># imports...</span>
<span class="c"># get host/port</span>
<span class="c"># init logging</span>
<span class="c"># grab --watch argv parameter, assign do_reload</span>

<span class="k">def</span> <span class="nf">socketio_serve</span><span class="p">():</span>
    <span class="n">cfgfile</span> <span class="o">=</span> <span class="s">&quot;file.ini&quot;</span>

    <span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
        <span class="n">app</span> <span class="o">=</span> <span class="n">paste</span><span class="o">.</span><span class="n">deploy</span><span class="o">.</span><span class="n">loadapp</span><span class="p">(</span><span class="s">&#39;config:</span><span class="si">%s</span><span class="s">&#39;</span> <span class="o">%</span> <span class="n">cfgfile</span><span class="p">,</span> <span class="n">relative_to</span><span class="o">=</span><span class="s">&#39;.&#39;</span><span class="p">)</span>
        <span class="n">server</span> <span class="o">=</span> <span class="n">socketio</span><span class="o">.</span><span class="n">SocketIOServer</span><span class="p">((</span><span class="n">host</span><span class="p">,</span> <span class="n">port</span><span class="p">),</span> <span class="n">app</span><span class="p">,</span>
                                         <span class="n">resource</span><span class="o">=</span><span class="s">&quot;socket.io&quot;</span><span class="p">)</span>

        <span class="k">print</span> <span class="s">&quot;Serving on </span><span class="si">%s</span><span class="s">:</span><span class="si">%d</span><span class="s"> (http://127.0.0.1:</span><span class="si">%d</span><span class="s">) ...&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">host</span><span class="p">,</span> <span class="n">port</span><span class="p">,</span> <span class="n">port</span><span class="p">)</span>
        <span class="n">server</span><span class="o">.</span><span class="n">serve_forever</span><span class="p">()</span>

   <span class="k">def</span> <span class="nf">reloader</span><span class="p">():</span>
        <span class="kn">from</span> <span class="nn">paste</span> <span class="kn">import</span> <span class="n">reloader</span>
        <span class="n">reloader</span><span class="o">.</span><span class="n">install</span><span class="p">()</span>
        <span class="n">reloader</span><span class="o">.</span><span class="n">watch_file</span><span class="p">(</span><span class="n">cfgfile</span><span class="p">)</span>
        <span class="k">for</span> <span class="n">lang</span> <span class="ow">in</span> <span class="n">glob</span><span class="o">.</span><span class="n">glob</span><span class="p">(</span><span class="s">&#39;*/locale/*/LC_MESSAGES/*.mo&#39;</span><span class="p">):</span>
            <span class="n">reloader</span><span class="o">.</span><span class="n">watch_file</span><span class="p">(</span><span class="n">lang</span><span class="p">)</span>

    <span class="n">jobs</span> <span class="o">=</span> <span class="p">[</span><span class="n">gevent</span><span class="o">.</span><span class="n">spawn</span><span class="p">(</span><span class="n">main</span><span class="p">)]</span>
    <span class="k">if</span> <span class="n">do_reload</span><span class="p">:</span>
        <span class="n">jobs</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">gevent</span><span class="o">.</span><span class="n">spawn</span><span class="p">(</span><span class="n">reloader</span><span class="p">))</span>
    <span class="n">gevent</span><span class="o">.</span><span class="n">joinall</span><span class="p">(</span><span class="n">jobs</span><span class="p">)</span>
</pre></div>





<p>This shows how Gevent handles concurrent jobs.  You spawn greenlets with <code>gevent.spawn()</code> and wait for them to terminate with <code>gevent.joinall()</code>.  The <code>reloader()</code> borrows the reloader code from paste (the same one used when running <code>paster serve --reload</code>) and will exit completely the program with error code number 3.  The <code>socketio-serve-reload</code> wraps around this program and catches those errors, and restarts the server when something is modified.</p>






<h3>Our Socket.IO aware application, client-side.</h3>

<p>Now, let's write some basic WebSocket code, directly in our <code>index.html</code>:</p>

<div class="fooevent"><span>socketio</span> YASnippet to copy the boilerplate</div>

<div class="fooevent"><span>socketio</span> Event to copy socket.io.js to ~/Foo/foo/static/js/socket.io.js, fitting with the boilerplate.</div>


<div class="pygments_tango"><pre>  <span class="o">&lt;</span><span class="nx">script</span> <span class="nx">src</span><span class="o">=</span><span class="s2">&quot;http://cdn.socket.io/stable/socket.io.js&quot;</span><span class="o">&gt;&lt;</span><span class="err">/script&gt;</span>

  <span class="o">&lt;</span><span class="nx">script</span><span class="o">&gt;</span>
    <span class="kd">var</span> <span class="nx">socket</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
    <span class="nx">$</span><span class="p">(</span><span class="nb">document</span><span class="p">).</span><span class="nx">ready</span><span class="p">(</span><span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
      <span class="nx">socket</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">io</span><span class="p">.</span><span class="nx">Socket</span><span class="p">(</span><span class="kc">null</span><span class="p">,</span> <span class="p">{});</span>

      <span class="nx">socket</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">&#39;connect&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
        <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&quot;Connected&quot;</span><span class="p">);</span>
        <span class="nx">socket</span><span class="p">.</span><span class="nx">send</span><span class="p">({</span><span class="nx">type</span><span class="o">:</span> <span class="s2">&quot;connect&quot;</span><span class="p">,</span> <span class="nx">userid</span><span class="o">:</span> <span class="mi">123</span><span class="p">});</span>
      <span class="p">});</span>
      <span class="nx">socket</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">&#39;message&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">obj</span><span class="p">)</span> <span class="p">{</span>
        <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&quot;Message&quot;</span><span class="p">,</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">obj</span><span class="p">));</span>
        <span class="k">if</span> <span class="p">(</span><span class="nx">obj</span><span class="p">.</span><span class="nx">type</span> <span class="o">==</span> <span class="s2">&quot;some&quot;</span><span class="p">)</span> <span class="p">{</span>
          <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&quot;do some&quot;</span><span class="p">);</span>
        <span class="p">}</span>
      <span class="p">});</span>
      <span class="nx">socket</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">&#39;error&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">obj</span><span class="p">)</span> <span class="p">{</span>
        <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&quot;Error&quot;</span><span class="p">,</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">obj</span><span class="p">));</span>
      <span class="p">});</span>
      <span class="nx">socket</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">&#39;disconnect&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
        <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&quot;Disconnected&quot;</span><span class="p">);</span>
      <span class="p">});</span>

      <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&quot;Connecting...&quot;</span><span class="p">);</span>
      <span class="nx">socket</span><span class="p">.</span><span class="nx">connect</span><span class="p">();</span>
    <span class="p">});</span>
  <span class="o">&lt;</span><span class="err">/script&gt;</span>
</pre></div>




<p>When the socket gets connected, we immediately send a message, with the type <code>connect</code>.  This will be mapped on the server side (by <code>pyramid_socketio</code>) to the <code>msg_connect</code> method in the <code>SocketIOContext</code> provided to <code>socketio_manage</code>.</p>

<p>The <code>null</code> value and empty object passed to <code>new io.Socket()</code> means we're going to connect to the same host and port as the current request, and the URL will be <code>/socket.io/...</code> with some extra path information like the transport being used, and the session ID (used by Socket.IO to maintain a channel open).</p>









<h3>The server-side socket.io handler</h3>

<p>Configuring socket.io in our Pyramid app goes like this:</p>


<div class="pygments_tango"><pre><span class="k">def</span> <span class="nf">main</span><span class="p">(</span><span class="o">...</span><span class="p">):</span>
    <span class="o">...</span>
    <span class="c">#config.add_static_view(&#39;socket.io/lib&#39;, &#39;foo:static&#39;)</span>
    <span class="n">config</span><span class="o">.</span><span class="n">add_route</span><span class="p">(</span><span class="s">&#39;socket_io&#39;</span><span class="p">,</span> <span class="s">&#39;socket.io/*remaining&#39;</span><span class="p">)</span>
    <span class="o">...</span>
</pre></div>




<p>If you want Flash fallback support as an alternative WebSockets implementation, uncomment the <code>add_static_view</code> call, to serve the <code>WebSocketMain.swf</code> file.  Setting this up is slightly more complicated, requires Flash installed on the client side, a Flash Policy Server on the server side, and an added javascript that you can get at: <a href="https://github.com/gimite/web-socket-js">https://github.com/gimite/web-socket-js</a>.  Check out this repository in <code>foo/static</code>:</p>


<div class="pygments_tango"><pre><span class="o">(</span>env<span class="o">)</span><span class="nv">$ </span><span class="c">## Optional, for Flash websockets fallback support</span>
<span class="o">(</span>env<span class="o">)</span><span class="nv">$ </span><span class="nb">cd </span>foo/static
<span class="o">(</span>env<span class="o">)</span><span class="nv">$ </span>git clone https://github.com/gimite/web-socket-js.git
<span class="o">(</span>env<span class="o">)</span><span class="nv">$ </span><span class="nb">cd</span> ../..
</pre></div>




<p>The <code>WebSocketMain.swf</code> file must be served from the same domain, otherwise, you'll have to use the insecure one, and change the location in your HTML output to something like:</p>


<div class="pygments_tango"><pre><span class="nt">&lt;script&gt;</span><span class="nx">WEB_SOCKET_SWF_LOCATION</span> <span class="o">=</span> <span class="s1">&#39;/path/to/WebSocketMainInsecure.swf&#39;</span><span class="p">;</span><span class="nt">&lt;/script&gt;</span>
</pre></div>




<p>If you want the Flash support, don't forget to add the <code>script</code> tag in your HTML file. See the documentation of <a href="https://github.com/gimite/web-socket-js">web-socket-js</a> for more info about these things.</p>

<p>You can turn off Flash fallback altogether by passing some parameters to your call to <code>io.Socket(null, {transports: ['websocket', 'flashsocket', 'htmlfile', 'xhr-multipart', 'xhr-polling', 'jsonp-polling']});</code>.</p>

<p>Back to Pyramid.  This is the basic setup to handle messages using the <code>pyramid_socketio</code> helpers:</p>

<div class="fooevent"><span>manage</span> Copy and paste the Socket.IO server-side boilerplate.</div>


<div class="pygments_tango"><pre><span class="c">### In views.py:</span>

<span class="kn">from</span> <span class="nn">pyramid.response</span> <span class="kn">import</span> <span class="n">Response</span>
<span class="kn">from</span> <span class="nn">pyramid_socketio.io</span> <span class="kn">import</span> <span class="n">SocketIOContext</span><span class="p">,</span> <span class="n">socketio_manage</span>
<span class="kn">import</span> <span class="nn">gevent</span>

<span class="k">class</span> <span class="nc">ConnectIOContext</span><span class="p">(</span><span class="n">SocketIOContext</span><span class="p">):</span>
    <span class="c"># self.io is the Socket.IO socket</span>
    <span class="c"># self.request is the request</span>
    <span class="k">def</span> <span class="nf">msg_connect</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">msg</span><span class="p">):</span>
        <span class="k">print</span> <span class="s">&quot;Connect message received&quot;</span><span class="p">,</span> <span class="n">msg</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s">&quot;connected&quot;</span><span class="p">,</span> <span class="n">hello</span><span class="o">=</span><span class="s">&quot;world&quot;</span><span class="p">)</span>

<span class="c"># Socket.IO implementation</span>
<span class="nd">@view_config</span><span class="p">(</span><span class="n">route_name</span><span class="o">=</span><span class="s">&quot;socket_io&quot;</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">socketio_service</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
    <span class="k">print</span> <span class="s">&quot;Socket.IO request running&quot;</span>
    <span class="n">retval</span> <span class="o">=</span> <span class="n">socketio_manage</span><span class="p">(</span><span class="n">ConnectIOContext</span><span class="p">(</span><span class="n">request</span><span class="p">))</span>
    <span class="k">return</span> <span class="n">Response</span><span class="p">(</span><span class="n">retval</span><span class="p">)</span>
</pre></div>




<p>The first section is a <em>SocketIOContext</em>, which is provided by the <code>pyramid_socketio</code> package.  It is a simple objects that maps incoming messages from the socket to class methods.  It also provides convenience methods like <code>spawn()</code>, <code>msg()</code> and <code>error()</code> to spawn a new greenlet, send a new packet (or message) or send an error message (in a pre-defined format).  The Socket.IO object itself, representing the socket, will be available via <code>self.io</code> (read <a href="https://bitbucket.org/Jeffrey/gevent-socketio/src/tip/socketio/protocol.py">gevent-socketio</a>'s documentation for more information on that object) and the original request for the socket will be held in <code>self.request</code>.  If you send a message like <code>{type: "connect", userid: 123}</code> from the web application, it will run the <code>msg_connect()</code> method with a dict representing your Javascript object as a second parameter.</p>

<p>The second section is the pyramid handler.  Once the <code>gevent-socketio</code> has done his job (of dealing with the abstraction of the transports), it will launch the request against the normal WSGI application, and will arrive, just like with a normal GET request, to one of ours views.  This is where we pass on the control to the <code>pyramid_socketio</code> manager.  The manager will listen for incoming packets, and dispatch to the <code>SocketIOContext</code> we've provided.</p>




<h3>Using Flot.js to load dynamic stats from the server</h3>

<p>What we want to do here is to graph some values coming from the server, being <em>pushed</em> to the client.  This paradigm will irrevocably change the way we consume and construct web application in the near future.</p>

<div class="fooevent"><span>flot</span> Open the Flot website with an example.</div>

<p><a href="http://code.google.com/p/flot/">Flot.js</a> is a nice graphs library that works completely on the client side. See it's website for more <a href="http://people.iola.dk/olau/flot/examples/">examples</a> and details.</p>

<p>Start by getting <code>jquery.flot.js</code> into your project:


<div class="pygments_tango"><pre><span class="o">(</span>env<span class="o">)</span><span class="nv">$ </span><span class="nb">cd</span> ~/Foo/foo/static
<span class="o">(</span>env<span class="o">)</span><span class="nv">$ </span>mkdir js
<span class="o">(</span>env<span class="o">)</span><span class="nv">$ </span><span class="nb">cd </span>js
<span class="o">(</span>env<span class="o">)</span><span class="nv">$ </span>wget http://people.iola.dk/olau/flot/jquery.flot.js
</pre></div>




<p>then let's add in our HTML template, <strong>after</strong> the code to load <code>jQuery</code> itself:</p>


<div class="pygments_tango"><pre>  <span class="nt">&lt;script </span><span class="na">src=</span><span class="s">&quot;${request.static_url(&#39;foo:static/js/jquery.flot.js&#39;)}&quot;</span><span class="nt">&gt;&lt;/script&gt;</span>
</pre></div>




<p>somewhere.  Add a placeholder for the graph somewhere in your page:</p>


<div class="pygments_tango"><pre>  <span class="nt">&lt;div</span> <span class="na">id=</span><span class="s">&quot;graph&quot;</span><span class="nt">&gt;&lt;/div&gt;</span>
</pre></div>




<p>Then, that could be the handler to display some basic data (put that under the Socket.IO stuff):</p>

<div class="fooevent"><span>data</span> YASnippet to add the values for d1, and d2</div>


<div class="pygments_tango"><pre>  <span class="o">&lt;</span><span class="nx">script</span><span class="o">&gt;</span>
    <span class="kd">var</span> <span class="nx">d1</span> <span class="o">=</span> <span class="p">[[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">],</span> <span class="p">[</span><span class="mi">2</span><span class="p">,</span> <span class="mi">4</span><span class="p">],</span> <span class="p">[</span><span class="mi">3</span><span class="p">,</span> <span class="mi">0</span><span class="p">],</span> <span class="p">[</span><span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">]];</span>
    <span class="kd">var</span> <span class="nx">d2</span> <span class="o">=</span> <span class="p">[[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">4</span><span class="p">],</span> <span class="p">[</span><span class="mi">2</span><span class="p">,</span> <span class="mi">6</span><span class="p">],</span> <span class="p">[</span><span class="mi">3</span><span class="p">,</span> <span class="mi">7</span><span class="p">],</span> <span class="p">[</span><span class="mi">4</span><span class="p">,</span> <span class="mi">2</span><span class="p">]];</span>
    <span class="nx">$</span><span class="p">.</span><span class="nx">plot</span><span class="p">(</span><span class="nx">$</span><span class="p">(</span><span class="s1">&#39;#graph&#39;</span><span class="p">),</span> <span class="p">[</span><span class="nx">d1</span><span class="p">,</span> <span class="nx">d2</span><span class="p">],</span> <span class="p">{});</span>
  <span class="o">&lt;</span><span class="err">/script&gt;</span>
</pre></div>




<p>If we modify <code>[d1, d2]</code> to <code>[{label: "Hello", data: d1}, d2]</code>, we'll have a label associated with it gratis.</p>

<p>Now we want to have some data fed from the server to the client, in real-time. Let's add a handler for messages labeled <code>showdata</code> on the client side.  That'll be in our <code>socket.on('message', ...)</code> handler:</p>


<div class="pygments_tango"><pre>      <span class="nx">socket</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">&#39;message&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">obj</span><span class="p">)</span> <span class="p">{</span>
        <span class="p">...</span>
        <span class="k">if</span> <span class="p">(</span><span class="nx">obj</span><span class="p">.</span><span class="nx">type</span> <span class="o">==</span> <span class="s2">&quot;showdata&quot;</span><span class="p">)</span> <span class="p">{</span>
          <span class="nx">d1</span><span class="p">.</span><span class="nx">push</span><span class="p">([</span><span class="nx">d1</span><span class="p">.</span><span class="nx">length</span><span class="p">,</span> <span class="nx">obj</span><span class="p">.</span><span class="nx">point</span><span class="p">]);</span>
          <span class="nx">$</span><span class="p">.</span><span class="nx">plot</span><span class="p">(</span><span class="nx">$</span><span class="p">(</span><span class="s1">&#39;#graph&#39;</span><span class="p">),</span> <span class="p">[{</span><span class="nx">label</span><span class="o">:</span> <span class="s2">&quot;Bob&quot;</span><span class="p">,</span> <span class="nx">data</span><span class="o">:</span> <span class="nx">d1</span><span class="p">}]);</span>
        <span class="p">}</span>
      <span class="p">});</span>
</pre></div>




<p>To have those values sent on the server side, we'll modify slightly our server-side code:</p>

<div class="fooevent"><span>sendcpu</span> YASnippet to add the 'sendcpu' stub.</div>


<div class="pygments_tango"><pre><span class="k">class</span> <span class="nc">ConnectIOContext</span><span class="p">(</span><span class="n">SocketIOContext</span><span class="p">):</span>
    <span class="o">...</span>
    <span class="k">def</span> <span class="nf">msg_connect</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">msg</span><span class="p">):</span>
        <span class="o">...</span>
        <span class="k">def</span> <span class="nf">sendcpu</span><span class="p">():</span>
            <span class="sd">&quot;&quot;&quot;Calculate CPU utilization&quot;&quot;&quot;</span>
            <span class="n">prev</span> <span class="o">=</span> <span class="bp">None</span>
            <span class="k">while</span> <span class="bp">self</span><span class="o">.</span><span class="n">io</span><span class="o">.</span><span class="n">connected</span><span class="p">():</span>
                <span class="n">vals</span> <span class="o">=</span> <span class="nb">map</span><span class="p">(</span><span class="nb">int</span><span class="p">,</span> <span class="p">[</span><span class="n">x</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="nb">open</span><span class="p">(</span><span class="s">&#39;/proc/stat&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">readlines</span><span class="p">()</span>
                                 <span class="k">if</span> <span class="n">x</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s">&#39;cpu &#39;</span><span class="p">)][</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">split</span><span class="p">()[</span><span class="mi">1</span><span class="p">:</span><span class="mi">5</span><span class="p">])</span>
                <span class="k">if</span> <span class="n">prev</span><span class="p">:</span>
                    <span class="n">percent</span> <span class="o">=</span> <span class="p">(</span><span class="mf">100.0</span> <span class="o">*</span> <span class="p">(</span><span class="nb">sum</span><span class="p">(</span><span class="n">vals</span><span class="p">[:</span><span class="mi">3</span><span class="p">])</span> <span class="o">-</span> <span class="nb">sum</span><span class="p">(</span><span class="n">prev</span><span class="p">[:</span><span class="mi">3</span><span class="p">]))</span> <span class="o">/</span> 
                               <span class="p">(</span><span class="nb">sum</span><span class="p">(</span><span class="n">vals</span><span class="p">)</span> <span class="o">-</span> <span class="nb">sum</span><span class="p">(</span><span class="n">prev</span><span class="p">)))</span>
                    <span class="bp">self</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s">&quot;showdata&quot;</span><span class="p">,</span> <span class="n">point</span><span class="o">=</span><span class="n">percent</span><span class="p">)</span>
                <span class="n">prev</span> <span class="o">=</span> <span class="n">vals</span>
                <span class="n">gevent</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">0.5</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">spawn</span><span class="p">(</span><span class="n">sendcpu</span><span class="p">)</span>
    <span class="o">...</span>
</pre></div>




<p>Except all the CPU usage calculation, there are two relevant parts here: the call to <code>self.spawn()</code> and the call to <code>self.msg()</code>.</p>

<p>The <code>spawn()</code> method allows us to spawn a new greenlet and attach it to the <code>SocketIOContext</code>, so that when we kill the Socket.IO session, we kill also all the greenlets that are related to it.  It helps prevent memory leaks.  It's a thin wrapper around <a href="http://www.gevent.org/gevent.html#gevent.spawn">gevent's spawn method</a> that keeps a reference in the <code>SocketIOContext</code>.</p>

<p>The call to <code>self.msg()</code> is a method provided by the <code>pyramid_socketio</code> package.  It takes as a first argument the <em>type</em> of the message, and everything specified as keyword arguments afterwards are used to create the JSON object that will be transmitted.  You can pass on lists, dicts, etc..</p>


<h3>What if...</h3>

<p>Remember in the last post, we were dealing with some FFmpeg video encoding, and we had it displayed in a <code>video</code> tag ?  What if we could receive a message when the video is done transcoding ?  Wouldn't it be cool if we could have such a simple implementation:</p>


<div class="pygments_tango"><pre>      <span class="nx">socket</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">&#39;message&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">obj</span><span class="p">)</span> <span class="p">{</span>
        <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&quot;Message&quot;</span><span class="p">,</span> <span class="nx">obj</span><span class="p">);</span>
        <span class="k">if</span> <span class="p">(</span><span class="nx">obj</span><span class="p">.</span><span class="nx">type</span> <span class="o">==</span> <span class="s2">&quot;video&quot;</span><span class="p">)</span> <span class="p">{</span>
          <span class="nx">go</span><span class="p">(</span><span class="nx">obj</span><span class="p">.</span><span class="nx">url</span><span class="p">);</span>
        <span class="p">}</span>
      <span class="p">});</span>
</pre></div>




<p>with slight tweaks to the <code>go()</code> function to handle an argument, which would be the URL to ask for the video:</p>


<div class="pygments_tango"><pre>        <span class="kd">function</span> <span class="nx">go</span><span class="p">(</span><span class="nx">url</span><span class="p">)</span> <span class="p">{</span>
          <span class="nx">$</span><span class="p">(</span><span class="s1">&#39;#video&#39;</span><span class="p">).</span><span class="nx">html</span><span class="p">(</span><span class="s1">&#39;&lt;div&gt;Video ready: &#39;</span> <span class="o">+</span> <span class="nx">url</span> <span class="o">+</span> <span class="s1">&#39;&lt;/div&gt;&lt;video controls preload src=&quot;&#39;</span> <span class="o">+</span> <span class="nx">url</span> <span class="o">+</span> <span class="s1">&#39;&quot; /&gt;&#39;</span><span class="p">);</span>
          <span class="p">...</span>
        <span class="p">}</span>
</pre></div>




<p>We'll do just that in the next episode.</p>

<p>If you would like us to implement anything you've seen here in a real-life project, or to kick start some of your projects, don't hesitate to send out an e-mail at <a href="mailto:contact@savoirfairelinux.com">contact@savoirfairelinux.com</a> mentioning this blog.  We'll be glad to help.</p>
]]></summary>
  </entry>
  <entry>
    <author>
      <name>Alexandre Bourget</name>
      <uri>http://blog.abourget.net</uri>
    </author>
    <title type="html"><![CDATA[New and hot, part 3: FFmpeg video, HTML5 and drag'n'drop encoding]]></title>
    <link rel="alternate" type="text/html" href="http://blog.abourget.net/2011/3/14/new-and-hot-part-3-ffmpeg-video-html5-drag-n-drop-encoding" />
    <id>tag:blog.abourget.net,2011-03-14:0026</id>
    <updated>2011-03-17T09:01:00Z</updated>
    <published>2011-03-14T15:15:00Z</published>
    <category scheme="http://blog.abourget.net" term="Python" />
    <category scheme="http://blog.abourget.net" term="Web development" />
    <summary type="html"><![CDATA[

<p>This is part 3 of my <a href="http://confoo.ca/en/2011/session/the-pylons-project-new-and-hot-stuff-live-demo">March 9th 2011 Confoo presentation</a>.  Refer to the <a href="/2011/3/09/new-and-hot-stuff-in-the-pylons-project/">Table of Contents</a> for the other parts.</p>


<h3>FFmpeg encoding of an uploaded video file</h3>

<p>In this part, we will create a drag'n'drop frame to upload a video file we've encoded with a phone, and have it transcoded server-side in WebM.  This way we'll be able to read it back in the browser.</p>

<p>Before doing any WebM related encoding, we need to make sure our FFmpeg encoding has support for it.  If yours doesn't have it in, then here are the steps needed to get one:</p>


<div class="pygments_tango"><pre><span class="nv">$ </span>wget http://webm.googlecode.com/files/libvpx-v0.9.5.tar.bz2
<span class="nv">$ </span>wget http://webm.googlecode.com/files/ffmpeg-0.6.1_libvpx-0.9.2-3.diff.gz
<span class="nv">$ </span>wget http://www.ffmpeg.org/releases/ffmpeg-0.6.1.tar.bz2
<span class="nv">$ </span>tar -jxvf ffmpeg-0.6.1.tar.bz2
<span class="nv">$ </span>gunzip ffmpeg-0.6.1_libvpx-0.9.2-3.diff.gz
<span class="nv">$ </span><span class="nb">cd </span>ffmpeg-0.6.1/
<span class="nv">$ </span>patch -p1 &lt; ffmpeg-0.6.1_libvpx-0.9.2-3.diff 
<span class="nv">$ </span><span class="nb">cd</span> ..
<span class="nv">$ </span>tar -jxvf libvpx-v0.9.5.tar.bz2 
<span class="nv">$ </span><span class="nb">cd </span>libvpx-v0.9.5/
<span class="nv">$ </span>sudo apt-get install yasm
<span class="nv">$ </span>./configure
<span class="nv">$ </span>make
<span class="nv">$ </span>sudo make install
<span class="nv">$ </span><span class="nb">cd</span> ../ffmpeg-0.6.1/
<span class="nv">$ </span><span class="c">## You&#39;ll need libavformat, libavcodec, libswscale, libavutil, libfaad, libfaac, libvorbis, libx264 and things like that.. </span>
<span class="nv">$ </span>./configure --enable-gpl --enable-version3 --enable-nonfree --enable-postproc --enable-pthreads --enable-x11grab --enable-libvorbis --enable-libvpx --prefix<span class="o">=</span><span class="nv">$PWD</span>
<span class="nv">$ </span><span class="c">### Optionally add --enable-libx264 if you want to.., you&#39;ll need libx264 dev packages.</span>
<span class="nv">$ </span>make -j 9
<span class="nv">$ </span>mv libvpx-*ffpreset ffpresets/
<span class="nv">$ </span>make install
<span class="nv">$ </span><span class="nb">export </span><span class="nv">FFMPEG</span><span class="o">=</span><span class="nv">$PWD</span>/bin/ffmpeg
</pre></div>




<p>We'll use this encoding line to transform my Nexus One's video recording into a web-ready media file:</p>


<div class="pygments_tango"><pre><span class="nv">$ $FFMPEG</span> -y -i <span class="s2">&quot;INPUT_FILE&quot;</span> -threads 8 -f webm -aspect 16:9 -vcodec libvpx -deinterlace -g 120 -level 216 -profile 0 -qmax 42 -qmin 10 -rc_buf_aggressivity 0.95 -vb 2M -acodec libvorbis -aq 90 -ac 2 /tmp/OUTPUT.webm
<span class="nv">$ </span><span class="c">## You can optionally take out the -deinterlace flag if you&#39;re dealing with progressive material.</span>
</pre></div>




<p>Now, we'll want to be able to upload a file from the web interface.  For that, we'll use the browser's drag'n'drop support.  Since we're lazy, we'll use <a href="http://stackoverflow.com/questions/2657653/drag-and-drop-file-upload-in-google-chrome-chromium">the method specified here</a> to speed up things.  We'll create an IFRAME with everything required to handle the drag'n'drop upload.  We'll call it <code>foo/templates/iframe.html</code>:</p>

<div class="fooevent"><span>iframe</span> YAsnippet to paste that file, need to add the % if request.POST: part</div>


<div class="pygments_tango"><pre><span class="nt">&lt;script&gt;</span>
<span class="c">&lt;!--</span>
  <span class="kd">var</span> <span class="nx">entered</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="o">--&gt;</span>
<span class="nt">&lt;/script&gt;</span>
<span class="nt">&lt;body</span> <span class="na">ondragenter=</span><span class="s">&quot;entered++;document.getElementById(&#39;uploadelement&#39;).style.display=&#39;block&#39;&quot;</span> <span class="na">ondragleave=</span><span class="s">&quot;entered--;if (!entered) document.getElementById(&#39;uploadelement&#39;).style.display=&#39;none&#39;&quot;</span><span class="nt">&gt;</span>
  <span class="nt">&lt;form</span> <span class="na">method=</span><span class="s">&quot;post&quot;</span> <span class="na">enctype=</span><span class="s">&quot;multipart/form-data&quot;</span> <span class="na">id=</span><span class="s">&quot;uploadform&quot;</span><span class="nt">&gt;</span>

    % if request.POST:
      <span class="nt">&lt;div&gt;</span>Uploaded, processing...<span class="nt">&lt;/div&gt;</span>
    % endif

    Drop a video file here to process...
    <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">&quot;file&quot;</span> <span class="na">id=</span><span class="s">&quot;uploadelement&quot;</span> <span class="na">name=</span><span class="s">&quot;file&quot;</span> <span class="na">onchange=</span><span class="s">&quot;if (this.value) { document.getElementById(&#39;uploadform&#39;).submit(); }&quot;</span> <span class="na">style=</span><span class="s">&quot;display:none;position:absolute;top:0;left:0;right:0;bottom:0;opacity:0;&quot;</span> <span class="nt">/&gt;</span>
  <span class="nt">&lt;/form&gt;</span>
<span class="nt">&lt;/body&gt;</span>
</pre></div>




<p>I've added the <code>% if request.POST</code>, some Mako markup that will show "Uploaded" when we submitted something to the form.</p>

<p>Note that the file-upload field is conveniently named <code>file</code>. We'll refer to that when we want to access the uploaded file.</p>

<p>In our <code>index.html</code> file, we'll add this snippet to create the drag'n'drop iframe, and a <code>video</code> tag for the video to be played:</p>


<div class="pygments_tango"><pre>    ...
    <span class="nt">&lt;div</span> <span class="na">id=</span><span class="s">&quot;main&quot;</span> <span class="na">role=</span><span class="s">&quot;main&quot;</span><span class="nt">&gt;</span>
      <span class="nt">&lt;div</span> <span class="na">id=</span><span class="s">&quot;video&quot;</span><span class="nt">&gt;&lt;/div&gt;</span>
      <span class="nt">&lt;iframe</span> <span class="na">src=</span><span class="s">&quot;${request.route_url(&#39;iframe&#39;)}&quot;</span><span class="nt">&gt;&lt;/iframe&gt;</span>
    <span class="nt">&lt;/div&gt;</span>
    ...
</pre></div>





<p>Then we'll need something to get it to the browser, so we'll use this little view in <code>views.py</code>:</p>


<div class="pygments_tango"><pre><span class="nd">@view_config</span><span class="p">(</span><span class="n">route_name</span><span class="o">=</span><span class="s">&quot;iframe&quot;</span><span class="p">,</span> <span class="n">renderer</span><span class="o">=</span><span class="s">&quot;iframe.html&quot;</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">get_iframe</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
    <span class="k">return</span> <span class="p">{}</span>
</pre></div>




<p>and this route configuration in <code>__init__.py</code>:</p>


<div class="pygments_tango"><pre><span class="k">def</span> <span class="nf">main</span><span class="p">(</span><span class="n">global_config</span><span class="p">,</span> <span class="o">**</span><span class="n">settings</span><span class="p">):</span>
    <span class="o">...</span>
    <span class="n">config</span><span class="o">.</span><span class="n">add_route</span><span class="p">(</span><span class="s">&#39;iframe&#39;</span><span class="p">,</span> <span class="s">&#39;iframe.html&#39;</span><span class="p">)</span>
    <span class="o">...</span>
</pre></div>




<p>This means we have a named route called <code>iframe</code> but the URL to reach it will be <code>/iframe.html</code>.  The named route is used only to map code to URL locations.</p>

<p>Now, here is everything required to get the encoding to work, in <code>views.py</code>:</p>

<div class="fooevent"><span>ffmpeg</span> YAsnippet which contains the FFMPEG command line, including quotes.</div>


<div class="pygments_tango"><pre><span class="c">### tweak get_iframe(), add encode_video():</span>

<span class="nd">@view_config</span><span class="p">(</span><span class="n">route_name</span><span class="o">=</span><span class="s">&quot;iframe&quot;</span><span class="p">,</span> <span class="n">renderer</span><span class="o">=</span><span class="s">&quot;iframe.html&quot;</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">get_iframe</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
    <span class="k">if</span> <span class="s">&#39;file&#39;</span> <span class="ow">in</span> <span class="n">request</span><span class="o">.</span><span class="n">params</span><span class="p">:</span>
        <span class="n">f</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">POST</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">&#39;file&#39;</span><span class="p">)</span>
        <span class="n">tmpfile</span> <span class="o">=</span> <span class="s">&#39;/tmp/video.mp4&#39;</span>
        <span class="nb">open</span><span class="p">(</span><span class="n">tmpfile</span><span class="p">,</span> <span class="s">&#39;w&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">f</span><span class="o">.</span><span class="n">file</span><span class="o">.</span><span class="n">read</span><span class="p">())</span>
        <span class="c"># send to ffmpeg...</span>
        <span class="n">encode_video</span><span class="p">(</span><span class="n">tmpfile</span><span class="p">)</span>
    <span class="k">return</span> <span class="p">{}</span>

<span class="k">def</span> <span class="nf">encode_video</span><span class="p">(</span><span class="n">filename</span><span class="p">):</span>
    <span class="kn">import</span> <span class="nn">subprocess</span>
    <span class="n">cmd</span> <span class="o">=</span> <span class="s">&#39;$FFMPEG -y -i </span><span class="si">%s</span><span class="s"> -threads 8 -f webm -aspect 16:9 -vcodec libvpx -deinterlace -g 120 -level 216 -profile 0 -qmax 42 -qmin 10 -rc_buf_aggressivity 0.95 -vb 2M -acodec libvorbis -aq 90 -ac 2 /tmp/output.webm&#39;</span>
    <span class="n">p</span> <span class="o">=</span> <span class="n">subprocess</span><span class="o">.</span><span class="n">Popen</span><span class="p">(</span><span class="n">cmd</span> <span class="o">%</span> <span class="n">filename</span><span class="p">,</span> <span class="n">shell</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
    <span class="n">p</span><span class="o">.</span><span class="n">communicate</span><span class="p">()</span>
</pre></div>




<p>Also, we'll need something to serve the video file itself (in <code>views.py</code>):</p>


<div class="pygments_tango"><pre><span class="nd">@view_config</span><span class="p">(</span><span class="n">route_name</span><span class="o">=</span><span class="s">&quot;video&quot;</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">get_video</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
    <span class="kn">from</span> <span class="nn">paste.fileapp</span> <span class="kn">import</span> <span class="n">FileApp</span>
    <span class="k">return</span> <span class="n">request</span><span class="o">.</span><span class="n">get_response</span><span class="p">(</span><span class="n">FileApp</span><span class="p">(</span><span class="s">&quot;/tmp/output.webm&quot;</span><span class="p">))</span>
</pre></div>




<p>and a way to wire-in the routes (in <code>__init__.py</code>):</p>


<div class="pygments_tango"><pre><span class="k">def</span> <span class="nf">main</span><span class="p">(</span><span class="n">global_config</span><span class="p">,</span> <span class="o">**</span><span class="n">settings</span><span class="p">):</span>
    <span class="o">...</span>
    <span class="n">config</span><span class="o">.</span><span class="n">add_route</span><span class="p">(</span><span class="s">&#39;video&#39;</span><span class="p">,</span> <span class="s">&#39;video.webm&#39;</span><span class="p">)</span>
    <span class="o">...</span>
</pre></div>




<p>Now all that's missing, is a way to actually see the video, so let's add a button to do that manually, once we know the video has been encoded.  We add the <code>go()</code> function that will start the playback, and add a <code>button</code> to call the function and we're set! We'll do that in <code>index.html</code>:</p>


<div class="pygments_tango"><pre>      ...
      <span class="nt">&lt;div</span> <span class="na">id=</span><span class="s">&quot;video&quot;</span><span class="nt">&gt;&lt;/div&gt;</span>

      <span class="nt">&lt;script&gt;</span>
        <span class="kd">function</span> <span class="nx">go</span><span class="p">()</span> <span class="p">{</span>
          <span class="nx">$</span><span class="p">(</span><span class="s1">&#39;#video&#39;</span><span class="p">).</span><span class="nx">html</span><span class="p">(</span><span class="s1">&#39;&lt;video controls preload src=&quot;/video.webm&quot; /&gt;&#39;</span><span class="p">);</span>
          <span class="nx">$</span><span class="p">(</span><span class="s1">&#39;#video video&#39;</span><span class="p">)[</span><span class="mi">0</span><span class="p">].</span><span class="nx">play</span><span class="p">();</span>
        <span class="p">}</span>
      <span class="nt">&lt;/script&gt;</span>
      <span class="nt">&lt;button</span> <span class="na">onclick=</span><span class="s">&quot;go()&quot;</span><span class="nt">&gt;</span>Add video<span class="nt">&lt;/button&gt;</span>

      <span class="nt">&lt;iframe</span> <span class="na">src=</span><span class="s">&quot;${request.route_url(&#39;iframe&#39;)}&quot;</span><span class="nt">&gt;&lt;/iframe&gt;</span>
      ...
</pre></div>




<p>There you go.  We now have some encoding going, and we're able to play it back in the web browser!</p>

<h3>What if...</h3>

<p>Now what if we could have real-time messaging with the application, to know what's going on over there?  Why not graph stats about the process, and have the video popped when it's done encoding ?  That'll be the concern of our next episodes.</p>

<p>If you would like us to implement anything you've seen here in a real-life project, or to kick start some of your projects, don't hesitate to send out an e-mail at <a href="mailto:contact@savoirfairelinux.com">contact@savoirfairelinux.com</a> mentioning this blog.  We'll be glad to help.</p>

]]></summary>
  </entry>
  <entry>
    <author>
      <name>Alexandre Bourget</name>
      <uri>http://blog.abourget.net</uri>
    </author>
    <title type="html"><![CDATA[New and hot, part 2: First Pyramid setup]]></title>
    <link rel="alternate" type="text/html" href="http://blog.abourget.net/2011/3/14/new-and-hot-part-2-pyramid-setup" />
    <id>tag:blog.abourget.net,2011-03-14:0025</id>
    <updated>2011-03-14T14:15:00Z</updated>
    <published>2011-03-14T14:15:00Z</published>
    <category scheme="http://blog.abourget.net" term="Python" />
    <category scheme="http://blog.abourget.net" term="Web development" />
    <summary type="html"><![CDATA[

<p>This is part 2 of my <a href="http://confoo.ca/en/2011/session/the-pylons-project-new-and-hot-stuff-live-demo">March 9th 2011 Confoo presentation</a>.  Refer to the <a href="/2011/3/09/new-and-hot-stuff-in-the-pylons-project/">Table of Contents</a> for the other parts.</p>

<h3>Pyramid installation</h3>

<h4>Setup of the "Foo" pyramid application</h4>

<p>We'll install those packages:</p>

<ul>
  <li><b>pyramid</b>: the web framework.</li>
  <li><b>mongokit</b>: which brings in pymongo, the low-level mongo driver.</li>
  <li><b>kombu</b>: for AMQP/RabbitMQ communication.  To be used later on.</li>
  <li><b>redis</b>: to access a Redis server.  Used in the last part of this presentation.</li>
  <li><b>pyramid_socketio</b>: pyramid and Socket.IO integration for real-time apps.  This will bring in all the Gevent machinery.  We'll use that later on also.</li>
</ul>

<p>First, we setup the virtual environment:</p>


<div class="pygments_tango"><pre><span class="nv">$ </span><span class="nb">cd</span> ~
<span class="nv">$ </span>virtualenv --distribute env
<span class="nv">$ </span>. env/bin/activate
</pre></div>




<blockquote>NOTE: each time you will see that <code>(env)</code> prompt prefix, it means we're in the virtual environment.  To activate it (after a reboot or whatever), run <code>. env/bin/activate</code> again.</blockquote>

<p>Then install what we need, create a new template and install it in the environment (in development mode):</p>


<div class="pygments_tango"><pre><span class="o">(</span>env<span class="o">)</span><span class="nv">$ </span>pip install pyramid mongokit kombu pyramid_socketio redis
<span class="o">(</span>env<span class="o">)</span><span class="nv">$ </span>paster create -t pyramid_starter Foo
...
<span class="o">(</span>env<span class="o">)</span><span class="nv">$ </span>python setup.py develop
<span class="o">(</span>env<span class="o">)</span><span class="nv">$ </span>paster serve --reload development.ini
</pre></div>




<p>You'll notice that Pyramid was made to use the same Paste server and configuration that we were used to in Pylons 1.0.  Let's have a look at the default page at: <a href="http://127.0.0.1:6543/">http://127.0.0.1:6543</a>.  Needless to say that it is much prettier than before!  We can have a sneak peek at <a href="http://docs.pylonsproject.org/projects/pyramid/1.0/">the documentation</a> to notice it is very extensive and beautifully laid out.  </p>

<div class="fooevent"><span>site</span> Show/load in the browser the project URL.</div>

<div class="fooevent"><span>docs</span> Show the pre-loaded documentation, or load it.</div>


<h3>Exploring the directory layout</h3>


<div class="pygments_tango"><pre><span class="o">(</span>env<span class="o">)</span><span class="nv">$ </span><span class="nb">cd </span>Foo
<span class="o">(</span>env<span class="o">)</span><span class="nv">$ </span>find .
.
./templates
./templates/mytemplate.pt
./static
./static/pyramid.png
./static/pyramid-small.png
./static/transparent.gif
./static/headerbg.png
./static/middlebg.png
./static/favicon.ico
./static/footerbg.png
./static/ie6.css
./static/pylons.css
./resources.py
./__init__.py
./views.py
./tests.py
</pre></div>




<p>A notable difference with the original Pylons 1.0, is that Pyramid doesn't impose <i>any</i> structure to the directories you layout.  It can easily create a one-file application, as well as allow you to lay your files in the way that fits best with your project.  This is very refreshing.</p>

<p>In the <code>pyramid_starter</code> template, the <code>model.py</code> was renamed to <code>resources.py</code>, but you could rename it as you wish.  Simply tweak <code>__init__.py</code> accordingly.</p>

<p>The <code>static/</code> directory contains all the static files, and replaces the <code>public/</code> directory of Pylons 1.0.</p>

<p><code>templates/</code> is our old templates holder, with snippets of HTML in the templating language you like the most.  Pyramid isn't stubborn about the templating language you choose - or decide not to choose.  It'll run the templating engine you want, based on the extension of your template files.  So you can have many templating languages in the same project.  By default, it uses the <a href="http://chameleon.repoze.org/">Chameleon templating engine</a>, an XML-based Zope Page Template and Genshi template compiler. </p>

<p>The central part of the projet is in <code>__init__.py</code>... the <code>foo</code> module itself.  That's where all the config and wires are tied in.  We'll add a couple of config items in here in a moment.</p>

<p>Notice in the <code>__init__.py</code> file that there's nothing about sessions (Beaker) and not much about databases.  That's because they're pluggable, and we'll add them as required.  Fear not, everything is thoroughly documented.</p>



<h3>Adding Mako support</h3>

<p>I love Mako, so we'll tack on Mako support:</p>


<div class="pygments_tango"><pre><span class="k">def</span> <span class="nf">main</span><span class="p">(</span><span class="n">global_config</span><span class="p">,</span> <span class="o">**</span><span class="n">settings</span><span class="p">):</span>
    <span class="o">...</span>
    <span class="n">config</span><span class="o">.</span><span class="n">add_renderer</span><span class="p">(</span><span class="s">&#39;.html&#39;</span><span class="p">,</span> <span class="s">&#39;pyramid.mako_templating.renderer_factory&#39;</span><span class="p">)</span>
    <span class="o">...</span>
</pre></div>




<p>This will make all future rendering of <code>.html</code> files use the Mako rendering engine.  I used .html just for convenience.  You might want to use the <code>.mako</code> extension if you want to integrate with other components well.</p>

<p>You'll want to add those config in <code>development.ini</code> to have the templates compiled once.  <code>mako.directories</code> is required for Mako to work.</p>


<div class="pygments_tango"><pre><span class="c">### inside Foo/development.ini</span>
<span class="k">[app:Foo]</span>
<span class="err">...</span>
<span class="na">mako.directories</span> <span class="o">=</span> <span class="s">foo:templates</span>
<span class="c">#mako.module_directory = %(here)s/data/templates</span>
<span class="err">...</span>
</pre></div>




<p>The second <code>mako.module_directory</code> is used to write compiled Mako files.  Make sure to use this in production, as it speeds things up a lot.</p>


<h3>Writing our first view</h3>

<p>This year, I'm not going to demonstrate Mako, so I'll simply load the excellent and highly recommended <a href="http://html5boilerplate.com/">HTML5 boiler-plate</a> (by Paul Irish) directly into my templates dir.</p>


<div class="pygments_tango"><pre><span class="nv">$ </span><span class="nb">cd</span> ~/Foo
<span class="nv">$ </span>git clone ~/build/html5-boilerplate
<span class="nv">$ </span>cp -r html5-boilerplate/* foo/static
<span class="nv">$ </span><span class="c"># We&#39;ll put index.html in the templates/ dir though..</span>
<span class="nv">$ </span>mv foo/static/index.html foo/templates
</pre></div>




<p>We will need to tweak the HTML5 boilerplate so that the URLs pointing to our scripts and resources use Pyramid's routing.  Get the <a href="/files/0025/html5boilerplate.patch">full patch here</a>.  This is a sneak peek:
</p>

<div class="fooevent"><span>html5</span> YAsnippet for a stripped-down version of the html5boilerplate.</div>


<div class="pygments_tango"><pre><span class="gd">--- a/foo/templates/index.html</span>
<span class="gi">+++ b/foo/templates/index.html</span>
<span class="gu">@@ -26,18 +26,18 @@</span>
   &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt;
 
   &lt;!-- Place favicon.ico &amp; apple-touch-icon.png in the root of your domain and delete these references --&gt;
<span class="gd">-  &lt;link rel=&quot;shortcut icon&quot; href=&quot;/favicon.ico&quot;&gt;</span>
<span class="gd">-  &lt;link rel=&quot;apple-touch-icon&quot; href=&quot;/apple-touch-icon.png&quot;&gt;</span>
<span class="gi">+  &lt;link rel=&quot;shortcut icon&quot; href=&quot;${request.static_url(&#39;foo:static/favicon.ico&#39;)}&quot;&gt;</span>
<span class="gi">+  &lt;link rel=&quot;apple-touch-icon&quot; href=&quot;${request.static_url(&#39;foo:static/apple-touch-icon.png&#39;)}&quot;&gt;</span>
</pre></div>




<p>You can apply it this way:</p>


<div class="pygments_tango"><pre><span class="o">(</span>env<span class="o">)</span><span class="nv">$ </span><span class="nb">cd</span> ~/Foo
<span class="o">(</span>env<span class="o">)</span><span class="nv">$ </span>patch -p1
</pre></div>




<p>and <i>paste</i> the patch in, then hit <code>Ctrl+D</code>.</p>

<p>We'll also add a little style in <code>foo/static/css/style.css</code> after the CSS resets.  There's a specially marked section for you:</p>

<p><em style="text-align: right;">In the demonstration, I'm actually using <a href="/files/foopres/yasnippets/nxml-mode/html5">a stripped-down version of the html5 boilerplate</a> (it's a <a href="http://code.google.com/p/yasnippet/">yasnippet</a> for Emacs).</em></p>

<div class="fooevent"><span>styles</span> Copy and paste in foo/static/css/style.css</div>


<div class="pygments_tango"><pre> <span class="c">/* Primary Styles</span>
<span class="c">    Author: Alexandre Bourget</span>
<span class="c"> */</span>
<span class="nt">div</span><span class="nf">#container</span> <span class="p">{</span>
  <span class="k">margin</span><span class="o">:</span> <span class="m">0</span> <span class="k">auto</span><span class="p">;</span>
  <span class="k">width</span><span class="o">:</span> <span class="m">800px</span><span class="p">;</span>
  <span class="k">border</span><span class="o">:</span> <span class="m">1px</span> <span class="k">solid</span> <span class="m">#aaa</span><span class="p">;</span>
  <span class="k">border</span><span class="o">-</span><span class="n">radius</span><span class="o">:</span> <span class="m">10px</span><span class="p">;</span>
  <span class="k">padding</span><span class="o">:</span> <span class="m">10px</span><span class="p">;</span>
  <span class="o">-</span><span class="n">webkit</span><span class="o">-</span><span class="n">box</span><span class="o">-</span><span class="n">shadow</span><span class="o">:</span> <span class="m">5px</span> <span class="m">5px</span> <span class="m">5px</span> <span class="m">#ddd</span><span class="p">;</span>
<span class="p">}</span>
<span class="nt">h1</span> <span class="p">{</span>
  <span class="k">text-shadow</span><span class="o">:</span> <span class="m">2px</span> <span class="m">2px</span> <span class="m">2px</span> <span class="m">#ddd</span><span class="p">;</span>
  <span class="k">font-size</span><span class="o">:</span> <span class="m">22px</span><span class="p">;</span>
  <span class="k">margin-bottom</span><span class="o">:</span> <span class="m">10px</span><span class="p">;</span>
<span class="p">}</span>
<span class="nt">footer</span> <span class="p">{</span>
  <span class="k">font-size</span><span class="o">:</span> <span class="m">10px</span><span class="p">;</span>
  <span class="k">text-align</span><span class="o">:</span> <span class="k">center</span><span class="p">;</span>
  <span class="k">margin-top</span><span class="o">:</span> <span class="m">15px</span><span class="p">;</span>
<span class="p">}</span>
<span class="nt">iframe</span> <span class="p">{</span>
  <span class="k">width</span><span class="o">:</span> <span class="m">780px</span><span class="p">;</span>
  <span class="k">height</span><span class="o">:</span> <span class="m">70px</span><span class="p">;</span>
  <span class="k">border</span><span class="o">:</span> <span class="m">1px</span> <span class="k">solid</span> <span class="nb">black</span><span class="p">;</span>
<span class="p">}</span>
<span class="nt">div</span><span class="nf">#graph</span> <span class="p">{</span>
  <span class="k">width</span><span class="o">:</span> <span class="m">750px</span><span class="p">;</span>
  <span class="k">height</span><span class="o">:</span> <span class="m">300px</span><span class="p">;</span>
<span class="p">}</span>
<span class="nt">div</span><span class="nf">#video</span> <span class="p">{</span>
  <span class="k">text-align</span><span class="o">:</span> <span class="k">center</span><span class="p">;</span>
<span class="p">}</span>
<span class="nt">video</span> <span class="p">{</span>
  <span class="k">width</span><span class="o">:</span> <span class="m">640px</span><span class="p">;</span>
  <span class="k">height</span><span class="o">:</span> <span class="m">480px</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>






<p>We'll go in <code>index.html</code> and add some hello world or something:</p>


<div class="pygments_tango"><pre>     ...
     <span class="nt">&lt;header&gt;</span>
       <span class="nt">&lt;h1&gt;</span>Hello Excellent World!<span class="nt">&lt;/h1&gt;</span>
     <span class="nt">&lt;/header&gt;</span>
     ...
</pre></div>




<p>Now let's add the required calls to show that on the front-page:</p>

<div class="fooevent"><span>view</span> YASnippet to add a new view</div>

<p>In <code>views.py</code>:</p>

<div class="pygments_tango"><pre><span class="kn">from</span> <span class="nn">pyramid.view</span> <span class="kn">import</span> <span class="n">view_config</span>

<span class="nd">@view_config</span><span class="p">(</span><span class="n">route_name</span><span class="o">=</span><span class="s">&quot;home&quot;</span><span class="p">,</span> <span class="n">renderer</span><span class="o">=</span><span class="s">&quot;index.html&quot;</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">home</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
    <span class="k">return</span> <span class="p">{</span><span class="s">&#39;boo&#39;</span><span class="p">:</span> <span class="s">&#39;ahh&#39;</span><span class="p">}</span>
</pre></div>




<p>In <code>__init__.py</code>:</p>


<div class="pygments_tango"><pre><span class="k">def</span> <span class="nf">main</span><span class="p">(</span><span class="o">...</span><span class="p">):</span>
    <span class="o">...</span>
    <span class="n">config</span><span class="o">.</span><span class="n">add_route</span><span class="p">(</span><span class="s">&#39;home&#39;</span><span class="p">,</span> <span class="s">&#39;&#39;</span><span class="p">)</span>
    <span class="n">config</span><span class="o">.</span><span class="n">scan</span><span class="p">(</span><span class="s">&#39;foo.views&#39;</span><span class="p">)</span>
    <span class="o">...</span>
</pre></div>




<p>and hop! <a href="http://localhost:6543">http://localhost:6543</a> should now answer the call</p>

<p>That's it for now!  But what if we could actually do someting interesting, like dragging a video file from the desktop and have it encoded on the server-side so that it could be played back via the web ?  We'll do just that in our next episode!</p>

<p>If you would like us to implement anything you've seen here in a real-life project, or to kick start some of your projects, don't hesitate to send out an e-mail at <a href="mailto:contact@savoirfairelinux.com">contact@savoirfairelinux.com</a> mentioning this blog.</p>

<p><b>UPDATE</b> May 3rd 2011: Simplified the Mako integration (from 2 lines to one).</p>
]]></summary>
  </entry>
  <entry>
    <author>
      <name>Alexandre Bourget</name>
      <uri>http://blog.abourget.net</uri>
    </author>
    <title type="html"><![CDATA[New and hot stuff in The Pylons Project]]></title>
    <link rel="alternate" type="text/html" href="http://blog.abourget.net/2011/3/09/new-and-hot-stuff-in-the-pylons-project" />
    <id>tag:blog.abourget.net,2011-03-09:0022</id>
    <updated>2011-04-01T09:51:00Z</updated>
    <published>2011-03-09T16:55:00Z</published>
    <category scheme="http://blog.abourget.net" term="Python" />
    <category scheme="http://blog.abourget.net" term="Web development" />
    <summary type="html"><![CDATA[

<p>This is the layout of a talk I gave at the Confoo conference on March 9th 2011, in Montreal, Canada.  There will be a post on each of the following topics, each covering about 7 minutes of my talk.  It will be accompanied by the video of the talk, as well as all the references, code and links.</p>

<h3>Table of contents</h3>
<ul>
  <li><a href="/2011/4/01/new-and-hot-part-1-meta-presentation/">Part 1: Meta-presentation, setup and tools used</a></li>
  <li><a href="/2011/3/14/new-and-hot-part-2-pyramid-setup/">Part 2: Pyramid: installation and app starter, html5boilerplate</a></li>
  <li><a href="/2011/3/14/new-and-hot-part-3-ffmpeg-video-html5-drag-n-drop-encoding/">Part 3: FFmpeg encoding, video tag, and drag'n'drop</a></li>
  <li><a href="/2011/3/17/new-and-hot-part-4-pyramid-socket-io-gevent/">Part 4: Python's Gevent, Socket.IO presentation, Pyramid implementation (client and server)</a></li>
  <li><a href="/2011/3/23/new-and-hot-part-5-mongodb-integration/">Part 5: MongoDB integration for a distributed filesystem</a></li>
  <li><!--a href="0028"-->Part 6 revisited: Messaging with AMQP, RabbitMQ setup and the Kombu python lib<!--/a--></li>
  <li><a href="/2011/3/31/new-and-hot-part-6-redis-publish-and-subscribe/">Part 6: Easier messaging with Redis and its PubSub</a></li>
  <li>Part 7: Android app as a Socket.IO client.</li>
</ul>

<p>I hope to publish all parts within a few days.  I just want to make sure they are proof-read.</p>

<p>All the series was tested with Google Chrome.  If something doesn't work with your favorite browser, you might want to try with Chrome.</p>

<p>Here is the YouTube presentation playlist:</p>

<div class="video" style="text-align: center;">
  <object width="480" height="385"><param name="movie" value="http://www.youtube.com/p/1AA86FF9B5E5C551?hl=fr_FR&fs=1"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/p/1AA86FF9B5E5C551?hl=fr_FR&fs=1" type="application/x-shockwave-flash" width="480" height="385" allowscriptaccess="always" allowfullscreen="true"></embed></object>
</div>

<p>UPDATED April 1st 2011: Added video, and links to part 1 and part 6.</p>








]]></summary>
  </entry>
  <entry>
    <author>
      <name>Alexandre Bourget</name>
      <uri>http://blog.abourget.net</uri>
    </author>
    <title type="html"><![CDATA[Pyramid and Mako: how to do i18n the Pylons way]]></title>
    <link rel="alternate" type="text/html" href="http://blog.abourget.net/2011/1/13/pyramid-and-mako:-how-to-do-i18n-the-pylons-way" />
    <id>tag:blog.abourget.net,2011-01-13:0023</id>
    <updated>2011-02-14T00:56:00Z</updated>
    <published>2011-01-13T21:07:00Z</published>
    <category scheme="http://blog.abourget.net" term="Python" />
    <category scheme="http://blog.abourget.net" term="Web development" />
    <summary type="html"><![CDATA[

<p>In reply to <a href="http://lindekleiv.wordpress.com/2011/01/09/enable-automatic-translations-mako/">this post</a> about the Pylons way to do translation using Pyramid, here is my code snippet so that you don't need to put the <code>request</code> object in, each time you want to translate something:</p>

<p><b>__init__.py:</b></p>


<div class="pygments_tango"><pre><span class="k">def</span> <span class="nf">main</span><span class="p">(</span><span class="o">...</span><span class="p">):</span>
    <span class="o">...</span>
    <span class="n">config</span><span class="o">.</span><span class="n">add_subscriber</span><span class="p">(</span><span class="s">&#39;YOURPROJECT.subscribers.add_renderer_globals&#39;</span><span class="p">,</span>
                          <span class="s">&#39;pyramid.events.BeforeRender&#39;</span><span class="p">)</span>
    <span class="n">config</span><span class="o">.</span><span class="n">add_subscriber</span><span class="p">(</span><span class="s">&#39;YOURPROJECT.subscribers.add_localizer&#39;</span><span class="p">,</span>
                          <span class="s">&#39;pyramid.events.NewRequest&#39;</span><span class="p">)</span>
</pre></div>




<p>or wherever the following <code>add_renderer_globals</code> will be.</p>

<p>Then add, let's say in <code>subscribers.py</code>:</p>


<div class="pygments_tango"><pre><span class="kn">from</span> <span class="nn">pyramid.i18n</span> <span class="kn">import</span> <span class="n">get_localizer</span><span class="p">,</span> <span class="n">TranslationStringFactory</span>

<span class="k">def</span> <span class="nf">add_renderer_globals</span><span class="p">(</span><span class="n">event</span><span class="p">):</span>
    <span class="o">...</span>
    <span class="n">request</span> <span class="o">=</span> <span class="n">event</span><span class="o">.</span><span class="n">request</span>
    <span class="n">event</span><span class="p">[</span><span class="s">&#39;_&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">translate</span>
    <span class="n">event</span><span class="p">[</span><span class="s">&#39;localizer&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">localizer</span>
    <span class="o">...</span>

<span class="n">tsf</span> <span class="o">=</span> <span class="n">TranslationStringFactory</span><span class="p">(</span><span class="s">&#39;YOUR_GETTEXT_DOMAIN&#39;</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">add_localizer</span><span class="p">(</span><span class="n">event</span><span class="p">):</span>
    <span class="n">request</span> <span class="o">=</span> <span class="n">event</span><span class="o">.</span><span class="n">request</span>
    <span class="n">localizer</span> <span class="o">=</span> <span class="n">get_localizer</span><span class="p">(</span><span class="n">request</span><span class="p">)</span>
    <span class="k">def</span> <span class="nf">auto_translate</span><span class="p">(</span><span class="n">string</span><span class="p">):</span>
        <span class="k">return</span> <span class="n">localizer</span><span class="o">.</span><span class="n">translate</span><span class="p">(</span><span class="n">tsf</span><span class="p">(</span><span class="n">string</span><span class="p">))</span>
    <span class="n">request</span><span class="o">.</span><span class="n">localizer</span> <span class="o">=</span> <span class="n">localizer</span>
    <span class="n">request</span><span class="o">.</span><span class="n">translate</span> <span class="o">=</span> <span class="n">auto_translate</span>
</pre></div>




<p>Now, in your Mako template, you'll be able to use the simple <code>${_(u"Translate this string please")}</code> without having to specify the <code>request</code> explicitly, as it's enclosed in this request's "_" function.  <code>localizer</code> will also be available for plural forms and fancy stuff.</p>

<p>This version will also allow you to use translation in your view code, using something like:</p>


<div class="pygments_tango"><pre><span class="k">def</span> <span class="nf">my_view</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
    <span class="n">_</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">translate</span>
    <span class="n">request</span><span class="o">.</span><span class="n">session</span><span class="o">.</span><span class="n">flash</span><span class="p">(</span><span class="n">_</span><span class="p">(</span><span class="s">&quot;Welcome home&quot;</span><span class="p">))</span>
    <span class="o">...</span>
</pre></div>




<p>Now for all that to work, you'll need to:</p>


<div class="pygments_tango"><pre><span class="o">(</span>env<span class="o">)</span><span class="nv">$ </span>pip install Babel
</pre></div>




<p>first, and also run these commands in your project's directory:</p>


<div class="pygments_tango"><pre><span class="o">(</span>env<span class="o">)</span><span class="nv">$ </span>python setup.py extract_messages
<span class="o">(</span>env<span class="o">)</span><span class="nv">$ </span>python setup.py init_catalog -l en
<span class="o">(</span>env<span class="o">)</span><span class="nv">$ </span>python setup.py init_catalog -l fr
<span class="o">(</span>env<span class="o">)</span><span class="nv">$ </span>python setup.py init_catalog -l es
<span class="o">(</span>env<span class="o">)</span><span class="nv">$ </span>python setup.py init_catalog -l it
<span class="o">(</span>env<span class="o">)</span><span class="nv">$ </span>python setup.py update_catalog
<span class="o">(</span>env<span class="o">)</span><span class="nv">$ </span>python setup.py compile_catalog
</pre></div>




<p>... for the langauges you need.  Note that the sub-directory of your project is <code>locale/</code> in Pyramid, and not <code>i18n/</code> as it was in Pylons.  You'll notice that in the default <code>setup.cfg</code> of a Pyramid project.</p>

<p>Lastly, you'll want to have your Mako files extracted when you run <code>extract_messages</code>, so add these to your <code>setup.py</code> (yes, <a href="http://babel.edgewall.org/wiki/Documentation/setup.html#id7">you read me right</a>, in <code>setup.py</code> so that Babel can use it when invoking it's commands):</p>


<div class="pygments_tango"><pre><span class="n">python</span> <span class="n">setup</span><span class="o">.</span><span class="n">py</span> 
<span class="n">setup</span><span class="p">(</span>
    <span class="o">...</span>
    <span class="n">install_requires</span><span class="o">=</span><span class="p">[</span>
        <span class="o">...</span>
        <span class="n">Babel</span><span class="p">,</span>
        <span class="o">...</span>
        <span class="p">],</span>
    <span class="n">message_extractors</span> <span class="o">=</span> <span class="p">{</span><span class="s">&#39;yourpackage&#39;</span><span class="p">:</span> <span class="p">[</span>
            <span class="p">(</span><span class="s">&#39;**.py&#39;</span><span class="p">,</span> <span class="s">&#39;python&#39;</span><span class="p">,</span> <span class="bp">None</span><span class="p">),</span>
            <span class="p">(</span><span class="s">&#39;templates/**.html&#39;</span><span class="p">,</span> <span class="s">&#39;mako&#39;</span><span class="p">,</span> <span class="bp">None</span><span class="p">),</span>
            <span class="p">(</span><span class="s">&#39;templates/**.mako&#39;</span><span class="p">,</span> <span class="s">&#39;mako&#39;</span><span class="p">,</span> <span class="bp">None</span><span class="p">),</span>
            <span class="p">(</span><span class="s">&#39;static/**&#39;</span><span class="p">,</span> <span class="s">&#39;ignore&#39;</span><span class="p">,</span> <span class="bp">None</span><span class="p">)]},</span>
    <span class="o">...</span>
    <span class="p">)</span>
</pre></div>




<p>Hope this helps.</p>

<p><b>UPDATED Jan 14th, 00:56</b>: Added support for in-view translation.</p>]]></summary>
  </entry>
  <entry>
    <author>
      <name>Alexandre Bourget</name>
      <uri>http://blog.abourget.net</uri>
    </author>
    <title type="html"><![CDATA[My new Blogofile blog]]></title>
    <link rel="alternate" type="text/html" href="http://blog.abourget.net/2011/1/11/my-new-blogofile-blog" />
    <id>tag:blog.abourget.net,2011-01-11:0021</id>
    <updated>2011-01-11T17:30:00Z</updated>
    <published>2011-01-11T17:30:00Z</published>
    <category scheme="http://blog.abourget.net" term="Python" />
    <category scheme="http://blog.abourget.net" term="Web development" />
    <summary type="html"><![CDATA[
<p>Hello all.</p>

<p>With every New Year comes new resolutions, and mine was to revamp my blog.  So here it is, shining new, and all with flat files.  It's computed using the awesome little blogging engine called <a href="http://www.blogofile.com">Blogofile</a>.  It's updated using Emacs and git, with a hook that automatically rebuilds every file from source files and Mako templates.<p>

<p>I migrated from a Zine blog which was leaking to death (probably due to a bad/weird paster setup of mine).  The whole operation took about 5 hours, including the migration of my 20 other blog posts.</p>

<p>It uses the <a href="http://disqus.com">Disqus commenting system</a> so it really doesn't need anything dynamic on the server side.<p>

<p>If things are wrong or have changed in an unexpected way, please leave a comment below. Thanks</p>

]]></summary>
  </entry>
</feed>

