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

<channel>
	<title>Memory Dump</title>
	<atom:link href="http://www.lorenzogil.com/blog/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.lorenzogil.com/blog</link>
	<description>a brain backup</description>
	<pubDate>Sat, 20 Feb 2010 20:57:43 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.7</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Funda de gafas. The making of.</title>
		<link>http://www.lorenzogil.com/blog/2010/02/20/funda-de-gafas-the-making-of/</link>
		<comments>http://www.lorenzogil.com/blog/2010/02/20/funda-de-gafas-the-making-of/#comments</comments>
		<pubDate>Sat, 20 Feb 2010 20:57:43 +0000</pubDate>
		<dc:creator>lgs</dc:creator>
		
		<category><![CDATA[Tiendas]]></category>

		<guid isPermaLink="false">http://www.lorenzogil.com/blog/?p=150</guid>
		<description><![CDATA[Últimamente ando liado con un proyecto en el trabajo así que el fin de semana pasado, aprovechando que estaba en Granada, con mis padres, decidí desconectar un poco y, con la ayuda de mi madre, fabricar una funda de gafas&#8230;. diferente.
Os dejo la secuencia de fotos con el making of de la funda.
También os dejo [...]]]></description>
			<content:encoded><![CDATA[<p>Últimamente ando liado con un proyecto en el trabajo así que el fin de semana pasado, aprovechando que estaba en Granada, con mis padres, decidí desconectar un poco y, con la ayuda de mi madre, fabricar una funda de gafas&#8230;. diferente.</p>
<p>Os dejo la secuencia de fotos con el making of de la funda.</p>

<a href='http://www.lorenzogil.com/blog/2010/02/20/funda-de-gafas-the-making-of/attachment/01/' title='01'><img src="http://www.lorenzogil.com/blog/wp-content/uploads/2010/02/01-150x150.jpg" width="150" height="150" class="attachment-thumbnail" alt="" /></a>
<a href='http://www.lorenzogil.com/blog/2010/02/20/funda-de-gafas-the-making-of/attachment/02/' title='02'><img src="http://www.lorenzogil.com/blog/wp-content/uploads/2010/02/02-150x150.jpg" width="150" height="150" class="attachment-thumbnail" alt="" /></a>
<a href='http://www.lorenzogil.com/blog/2010/02/20/funda-de-gafas-the-making-of/attachment/03/' title='03'><img src="http://www.lorenzogil.com/blog/wp-content/uploads/2010/02/03-150x150.jpg" width="150" height="150" class="attachment-thumbnail" alt="" /></a>
<a href='http://www.lorenzogil.com/blog/2010/02/20/funda-de-gafas-the-making-of/attachment/04/' title='04'><img src="http://www.lorenzogil.com/blog/wp-content/uploads/2010/02/04-150x150.jpg" width="150" height="150" class="attachment-thumbnail" alt="" /></a>
<a href='http://www.lorenzogil.com/blog/2010/02/20/funda-de-gafas-the-making-of/attachment/05/' title='05'><img src="http://www.lorenzogil.com/blog/wp-content/uploads/2010/02/05-150x150.jpg" width="150" height="150" class="attachment-thumbnail" alt="" /></a>
<a href='http://www.lorenzogil.com/blog/2010/02/20/funda-de-gafas-the-making-of/attachment/06/' title='06'><img src="http://www.lorenzogil.com/blog/wp-content/uploads/2010/02/06-150x150.jpg" width="150" height="150" class="attachment-thumbnail" alt="" /></a>
<a href='http://www.lorenzogil.com/blog/2010/02/20/funda-de-gafas-the-making-of/attachment/07/' title='07'><img src="http://www.lorenzogil.com/blog/wp-content/uploads/2010/02/07-150x150.jpg" width="150" height="150" class="attachment-thumbnail" alt="" /></a>
<a href='http://www.lorenzogil.com/blog/2010/02/20/funda-de-gafas-the-making-of/attachment/08/' title='08'><img src="http://www.lorenzogil.com/blog/wp-content/uploads/2010/02/08-150x150.jpg" width="150" height="150" class="attachment-thumbnail" alt="" /></a>
<a href='http://www.lorenzogil.com/blog/2010/02/20/funda-de-gafas-the-making-of/attachment/09/' title='09'><img src="http://www.lorenzogil.com/blog/wp-content/uploads/2010/02/09-150x150.jpg" width="150" height="150" class="attachment-thumbnail" alt="" /></a>
<a href='http://www.lorenzogil.com/blog/2010/02/20/funda-de-gafas-the-making-of/attachment/10/' title='10'><img src="http://www.lorenzogil.com/blog/wp-content/uploads/2010/02/10-150x150.jpg" width="150" height="150" class="attachment-thumbnail" alt="" /></a>
<a href='http://www.lorenzogil.com/blog/2010/02/20/funda-de-gafas-the-making-of/attachment/11/' title='11'><img src="http://www.lorenzogil.com/blog/wp-content/uploads/2010/02/11-150x150.jpg" width="150" height="150" class="attachment-thumbnail" alt="" /></a>
<a href='http://www.lorenzogil.com/blog/2010/02/20/funda-de-gafas-the-making-of/attachment/12/' title='12'><img src="http://www.lorenzogil.com/blog/wp-content/uploads/2010/02/12-150x150.jpg" width="150" height="150" class="attachment-thumbnail" alt="" /></a>

<p>También os dejo <a href="http://www.lorenzogil.com/blog/wp-content/uploads/2010/02/patron-funda-1.svg">los planos en vectorial</a> por si alguno se anima. Estos planos se han mejorado tras la primera funda. Mi madre ya está deseando hacer más para mejorar el resultado.</p>
<p>Nota: la <a href="http://www.wiinintendo.net/2010/01/08/snes-eye-glasses-case-nes-iphone-case/" target="_self">inspiración original es esta</a>. Me gustó tanto que fui a comprarmela pero en aquel momento no tenían en stock así que me puse manos a la obra y seguí el principio punki del &#8220;do it yourself&#8221;.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.lorenzogil.com/blog/2010/02/20/funda-de-gafas-the-making-of/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Uso del DNIe en Fedora 11</title>
		<link>http://www.lorenzogil.com/blog/2009/10/28/uso-del-dnie-en-fedora-11/</link>
		<comments>http://www.lorenzogil.com/blog/2009/10/28/uso-del-dnie-en-fedora-11/#comments</comments>
		<pubDate>Wed, 28 Oct 2009 12:21:56 +0000</pubDate>
		<dc:creator>lgs</dc:creator>
		
		<category><![CDATA[Ordenadores]]></category>

		<category><![CDATA[dnie]]></category>

		<category><![CDATA[fedora]]></category>

		<guid isPermaLink="false">http://www.lorenzogil.com/blog/?p=137</guid>
		<description><![CDATA[Hoy he intentado usar mi DNI electrónico en mi sistema operativo Fedora 11 y me entristece decir que no ha sido fácil y una vez más quedamos relegados a este gueto que es el software libre. ¿Por qué? Muy fácil, el driver del DNI electrónico no es libre y eso hace que su distribución esté [...]]]></description>
			<content:encoded><![CDATA[<p>Hoy he intentado usar mi DNI electrónico en mi sistema operativo Fedora 11 y me entristece decir que no ha sido fácil y una vez más quedamos relegados a este gueto que es el software libre. ¿Por qué? Muy fácil, el driver del DNI electrónico no es libre y eso hace que su distribución esté totalmente ligada a un conjunto específico de versiones muy limitado de las librerías de las que depende. Cuando trabajé en el soporte del DNIe para Guadalinex v4 ya descubrimos este problema y nos resignamos a admitir que el DNIe iba a funcionar con la Guadalinex recién instalada pero probablemente dejaría de hacerlo cuando se actualizaran ciertas librerías del sistema, algo relativamente frecuente en cualquier distribución de Linux.</p>
<p>Parece que este problema no existe en el mundo Windows ya que las actualizaciones son mucho menos frecuentes y la gente del DNIe puede permitirse el lujo de distribuir un binario que funcionará durante al menos 3 o 4 años que es lo que suele durar una versión de este sistema operativo, frente a los 6-8 meses que duran las distribuciones de Linux. Es justo admitir que no es fácil seguir el ritmo de evolución de una distribución Linux pero también hay que recordar que este problema desaparecería si el código en cuestión fuera libre y se distribuyeran las fuentes listas para compilar con cualquier versión de las librerías implicadas.</p>
<p>Bueno, basta de quejas y vamos a lo que interesa, a hacer que funcione.</p>
<p>Lo primero es descargarnos los <a href="http://www.dnielectronico.es/descargas/PKCS11_para_Sistemas_Unix/opensc_1.4.6_arq_fed_10_32.html" target="_self">binarios para Fedora 10</a> que es lo más reciente que hay en la página de la policia. En este punto debemos sentirnos afortunados de ser usuarios de una de las tres distribuciones de Linux soportadas: Debian, Ubuntu y Fedora. La verdad, no sé como lo hará la gente de Gentoo, Suse, Mandriva, o Arch, por citar algunas de las más populares.</p>
<p>Desempaquetamos el tar y obtenemos dos paquetes rpm:</p>
<ul>
<li>opensc-0.11.7-7.fc10.i386.rpm</li>
<li>opensc-dnie-1.4.6-2.fc10.i386.rpm</li>
</ul>
<p>Al intentar instalar el primero tendremos un error de dependencias:</p>
<pre>[root@ticotico ~]# rpm -Uvh --force opensc-0.11.7-7.fc10.i386.rpm
error: Error de dependencias:
libcrypto.so.7 se necesita para opensc-0.11.7-7.fc10.i386
libltdl.so.3 se necesita para opensc-0.11.7-7.fc10.i386</pre>
<p>Y lo que está ocurriendo aquí es que las librerías libcrypto (paquete openssl) y libtdl (paquete libtool-ltdl) instaladas en mi sistema son más recientes que esas. Ahora nos toca forzar la instalación de opensc-0.11.7 aún sabiendo que es peor que opensc 0.11.8 que es la versión que ofrece Fedora 11, ya que la <a href="http://lwn.net/Alerts/335402/" target="_self">versión 0.11.7 tiene vulnerabilidades de seguridad</a>. Los chicos del DNIe dicen que no liberan el código porque sería inseguro hacerlo así pero no actualizan su paquete haciendo que tengamos que usar librerías con fallos de seguridad. Una vez más, la seguridad por oscuridad triunfa. Un driver para atarnos a todos al reino de las sombras.</p>
<p>No nos desviemos, tras desinstalar nuestro querido opensc-0.11.8 de Fedora 11 instalaremos la versión 0.11.7:</p>
<pre>[root@ticotico ~]# yum remove opensc
[root@ticotico ~]# rpm -Uvh --nodeps opensc-0.11.7-7.fc10.i386.rpm
Preparando...               ########################################### [100%]
   1:opensc                 ########################################### [100%]</pre>
<p>Ahora bien, ahora tenemos que arreglar a mano el problema de las dependencias. Rezaremos para que las nuevas versiones de libcrypto y libtdll sean compatibles hacia atras. Con el comando ldd vemos si opensc tiene sus dependencias disponibles:</p>
<pre>[root@ticotico ~]# ldd /usr/bin/opensc-tool
linux-gate.so.1 =&gt;  (0x00525000)
libopensc.so.2 =&gt; /usr/lib/libopensc.so.2 (0x00dd8000)
libcrypto.so.7 =&gt; not found
libopenct.so.1 =&gt; /usr/lib/libopenct.so.1 (0x00d19000)
libz.so.1 =&gt; /lib/libz.so.1 (0x00318000)
libltdl.so.3 =&gt; not found
libdl.so.2 =&gt; /lib/libdl.so.2 (0x002f4000)
libscconf.so.2 =&gt; /usr/lib/libscconf.so.2 (0x00496000)
libpthread.so.0 =&gt; /lib/libpthread.so.0 (0x002fb000)
libc.so.6 =&gt; /lib/libc.so.6 (0x00157000)
/lib/ld-linux.so.2 (0x0012f000)
libcrypto.so.7 =&gt; not found
libltdl.so.3 =&gt; not found</pre>
<p>Como era de esperar no encuentra ni libcrypto ni libtdl. Hacemos enlaces simbólicos para facilitarle la tarea:</p>
<pre>[root@ticotico ~]# cd /usr/lib
[root@ticotico lib]# ln -s libltdl.so.7 libltdl.so.3
[root@ticotico lib]# ln -s libcrypto.so.8 libcrypto.so.7</pre>
<p>Probamos otra vez con ldd:</p>
<pre>[root@ticotico lib]# ldd /usr/bin/opensc-tool
linux-gate.so.1 =&gt;  (0x009d2000)
libopensc.so.2 =&gt; /usr/lib/libopensc.so.2 (0x00670000)
libcrypto.so.7 =&gt; /usr/lib/libcrypto.so.7 (0x05e96000)
libopenct.so.1 =&gt; /usr/lib/libopenct.so.1 (0x00b19000)
libz.so.1 =&gt; /lib/libz.so.1 (0x00318000)
libltdl.so.3 =&gt; /usr/lib/libltdl.so.3 (0x063ea000)
libdl.so.2 =&gt; /lib/libdl.so.2 (0x002f4000)
libscconf.so.2 =&gt; /usr/lib/libscconf.so.2 (0x00897000)
libpthread.so.0 =&gt; /lib/libpthread.so.0 (0x002fb000)
libc.so.6 =&gt; /lib/libc.so.6 (0x00157000)
/lib/ld-linux.so.2 (0x0012f000)</pre>
<p>Ahora ya podemos instalar el paquete del DNIe y hacerlo funcionar según las instrucciones oficiales:</p>
<pre>[root@ticotico ~]# rpm -Uvh opensc-dnie-1.4.6-2.fc10.i386.rpm
Preparando...               ########################################### [100%]
   1:opensc-dnie            ########################################### [100%]</pre>
<p>Ahora ya sólo nos queda validar el certificado en la página de pruebas: <a href="http://www.dnielectronico.es/como_utilizar_el_dnie/verificar.html" target="_self">http://www.dnielectronico.es/como_utilizar_el_dnie/verificar.html</a></p>
<h3>Actualización 29 Octubre 2009</h3>
<p>Después de todo el follón para tener funcionando el DNIe que tuve ayer resulta que los certificados digitales que hay dentro me han caducado desde hace 4 meses. Parece que los certificados tienen una validez de 30 meses mientras que la tarjeta en sí vale para 4 años. No me preguntéis por qué, yo tampoco lo entiendo.</p>
<p>Así que tras haber despotricado sobre el driver del DNIe me parece justo alabar el proceso de renovación de los certificados porque aquí sí que creo que han hecho un estupendo trabajo los responsables del DNIe. He ido a la comisaría  más cercana de mi casa, en Sevilla, y aunque no estaba abierta al público aún (eran las 7:40 de la mañna) un policía bastante amable me ha preguntado que qué quería y tras explicarle lo de la renovación de los certificados del DNIe me ha dejado pasar para que lo hiciera yo mismo con un quiosco diseñado para tal fin. Una vez en el quiosco la experiencia de usuario ha sido magnífica y tras poner el dedo en el lector de huellas me ha renovado los dos certificados sin problema. Ha tardado un poco pero bueno, más vale lento pero que sea fiable y no pete. Mi satisfacción se debe por tanto a:</p>
<ol>
<li>Un estupendo trabajo con el quiosco tanto hardware como software.</li>
<li>Un funcionario amable (el policia, en este caso) que me pregunta qué necesito y me permite usar un servicio aunque no haya comenzado el horario de atención al público.</li>
<li>Una ausencia total de espera, en parte debido a la hora, pero también a que se elimina la intervención de funcionarios para esta tarea.</li>
<li>Un ahorro para la administración pública al no necesitar de funcionarios para renovar estos certificados.</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://www.lorenzogil.com/blog/2009/10/28/uso-del-dnie-en-fedora-11/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Pycha padding present and future</title>
		<link>http://www.lorenzogil.com/blog/2009/09/13/pycha-padding-present-and-future/</link>
		<comments>http://www.lorenzogil.com/blog/2009/09/13/pycha-padding-present-and-future/#comments</comments>
		<pubDate>Sun, 13 Sep 2009 17:50:41 +0000</pubDate>
		<dc:creator>lgs</dc:creator>
		
		<category><![CDATA[Ordenadores]]></category>

		<guid isPermaLink="false">http://www.lorenzogil.com/blog/?p=128</guid>
		<description><![CDATA[Simon Ilyushchenko sent me a patch some weeks ago about tick labels in Pycha. The patch fixes the label position in the case where it goes out of the surface dimensions. The problem with his patch is that is too specific and only works well for the most simple case. For example, it doesn&#8217;t solve [...]]]></description>
			<content:encoded><![CDATA[<p>Simon Ilyushchenko sent me a patch some weeks ago about tick labels in Pycha. The patch fixes the label position in the case where it goes out of the surface dimensions. The problem with his patch is that is too specific and only works well for the most simple case. For example, it doesn&#8217;t solve the problem:</p>
<ul>
<li> when you have rotated labels</li>
<li> when you have pie charts</li>
<li> for the y axis tick labels</li>
</ul>
<p>And that&#8217;s why I didn&#8217;t add his patch to pycha. When developing the library I always try to make it as orthogonal and predictable as possible, so if a feature is added and it should work in all places where it makes sense. Users that send me patches are not usually concerned about edge cases but that&#8217;s my work as the library author and maintainer.</p>
<p>But the real point is that Simon raised a real issue with Pycha that I was worried about since the very beginning: right now the user has to adjust the padding options to make sure that tick labels and other things are kept inside the surface. Clearly this is suboptimal and for automatically computed charts without human intervention it can be a real issue.</p>
<p>So let me explain how pycha uses its real state space right now. First, the user tells the library how big the rendering surface is going to be: let&#8217;s call these parameters surface_width and surface_height. Then there are these padding options: padding.top, padding.bottom, padding.left and padding.right. Let&#8217;s see it in the following figure:</p>
<p><img class="aligncenter size-full wp-image-132" title="figure1" src="http://www.lorenzogil.com/blog/wp-content/uploads/2009/09/figure1.png" alt="figure1" width="462" height="289" /></p>
<p>Now we have a padding area and a chart area. The chart area is where pycha draws the chart. The axis (when used) are drawn in the boundary of the chart area and the tick labels and axis titles are drawn in the padding rectangle. Other things like the chart title and the legend are also drawn in that rectangle. You can see it in the next figure where the chart area has a blue background:</p>
<p><img class="aligncenter size-full wp-image-133" title="figure2" src="http://www.lorenzogil.com/blog/wp-content/uploads/2009/09/figure2.png" alt="figure2" width="462" height="257" /></p>
<p>Now, I want to change this and make Pycha automatically compute all its elements so the padding is actually that, blank space. Optimally Pycha should not draw anything into the padding rectangle. Well, there maybe some exceptions, see the end of this post for more information about them. So let&#8217;s define some new areas:</p>
<p><img class="aligncenter size-full wp-image-134" title="figure3" src="http://www.lorenzogil.com/blog/wp-content/uploads/2009/09/figure3.png" alt="figure3" width="462" height="289" /></p>
<p>The goal is to make Pycha compute all these areas automatically so the chart area is reduced to accomodate all the other things the library draws in the surface without cluttering the padding area. This is a big change and it won&#8217;t happen for 0.5.2 but I&#8217;ll try to have it for the 0.6.0 release. Obviously this is a backwards incompatible change and new charts rendered with the same options will look smaller. Maybe I&#8217;ll set the default values for the padding options to zero to minimize the update impact.</p>
<p>The way Pycha will compute these areas is actually pretty similar than the way graphical toolkits like Gtk+, Tk, Qt, Swing, GWT do it when using layout containers where the widgets are placed in. There is a layout phase where the area&#8217;s dimensions are negociated and calculated and then there is a rendering phase when the elements/widgets are actually drawn. For bar and line charts this may look overkill but for other charts like pie charts is really the only sane way to do it.</p>
<p>The legend is a special case and I&#8217;m still not sure about positioning it using &#8216;absolute&#8217; coordinates or give it its own area that is taken into account for the layout algorithm.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.lorenzogil.com/blog/2009/09/13/pycha-padding-present-and-future/feed/</wfw:commentRss>
		</item>
		<item>
		<title>There are more than one way to do it</title>
		<link>http://www.lorenzogil.com/blog/2009/04/19/there-are-more-than-one-way-to-do-it/</link>
		<comments>http://www.lorenzogil.com/blog/2009/04/19/there-are-more-than-one-way-to-do-it/#comments</comments>
		<pubDate>Sun, 19 Apr 2009 18:48:57 +0000</pubDate>
		<dc:creator>lgs</dc:creator>
		
		<category><![CDATA[Ordenadores]]></category>

		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://www.lorenzogil.com/blog/?p=110</guid>
		<description><![CDATA[I wrote a method the other day. It was not a particularly difficult method and before writing it, it didn&#8217;t seem like a challenge. When I finished it, it looked quite good and simple but there was something that keep my eyes focused on a point instead of enjoying the method as a whole. Something [...]]]></description>
			<content:encoded><![CDATA[<p>I wrote a method the other day. It was not a particularly difficult method and before writing it, it didn&#8217;t seem like a challenge. When I finished it, it looked quite good and simple but there was something that keep my eyes focused on a point instead of enjoying the method as a whole. Something similar as when you buy a shiny beatiful monitor, you plug it in and you discover it has a dead pixel. No matter how bright and fast your monitor is, that rotten pixel is ruining your experience.</p>
<p>Let me show you my broken pixel.</p>
<p>But before I&#8217;ll give you a small explanation of what the method does. Its class has a list of collectors, where each collector is a callable that return a generator of photos . The method collect the photos of all collectors until a maximum is reached, then it return the photos using an auxiliar method that does its own job postprocesing the list of photos.</p>
<div id="attachment_118" class="wp-caption aligncenter" style="width: 486px"><a href="http://www.lorenzogil.com/blog/wp-content/uploads/2009/04/carrusel.jpg"><img class="size-full wp-image-118" title="carrusel" src="http://www.lorenzogil.com/blog/wp-content/uploads/2009/04/carrusel.jpg" alt="Example carrusel" width="476" height="68" /></a><p class="wp-caption-text">Example carrusel</p></div>
<p>Here is my initial version:</p>
<pre><code>
    def collect_photos1(self, destination):
        n_photos_collected = 0
        for collector in self.collectors:
            for photo_info in collector(destination):
                self.add_photo(photo_info)
                n_photos_collected += 1
                if n_photos_collected &gt; self.max:
                    return self.get_photos()

        return self.get_photos()
</code></pre>
<p>As you can see, no rocket science so far. It&#8217;s just a nested for loop that iterates over all the photos until we get as many as we want. The rotten pixel is the return self.get_photos() line. It is bad because it&#8217;s duplicated, one in the finished condition and one at the end of the method. There are two problems with that duplication:</p>
<ul>
<li>The first one is a practical problem. What if, in the future, the get_photos aux method need to receive a parameter. We need to update the call to that method, but as we have two calls there is a chance that we forget to update one of them. If we had only one the error probability of an update would be lower.</li>
<li>The second problem is a theorical one. We are using a nested for loop to iterate over a list of lists of photos but we do not know in advance how long those lists are and how many loop body we are going to iterate.</li>
</ul>
<p>My second version is basically the same as the first but instead of duplicating the return self.get_photos line we are duplicating the break condition. Now, if we add a parameter to the get_photos method we will have to update just one call. But if we want to add another condition to stop collecting photos we will have to update two if statements. In other words, this version is pretty much the same.</p>
<pre><code>
    def collect_photos2(self, destination):
        n_photos_collected = 0
        for collector in self.collectors:
            for photo_info in collector(destination):
                self.add_photo(photo_info)
                n_photos_collected += 1
                if n_photos_collected &gt; self.max:
                    break
            if n_photos_collected &gt; self.max:
                break

        return self.get_photos()
</code></pre>
<p>Then I tried to convert the for loops into while loops since basic computer science tell us that a while loop is the choice to make when the number of iterations is unknown. So this version does not have the previous two problems and it&#8217;s easier to maintain. Nevertheless, it introduces another problem: it&#8217;s harder to read and to understand.</p>
<pre><code>
    def collect_photos3(self, destination):
        n_photos_collected = 0
        need_more_photos = True
        collectors_iterator = iter(self.collectors)
        while need_more_photos and collectors_iterator.has_next():
            collector = collectors_iterator.next()

            photos_iterator = collector(destination)
            while need_more_photos and photos_iterator.has_next():
                photo_info = photos_iterator.next()
                self.add_photo(photo_info)
                n_photos_collected += 1

                if n_photos_collected &gt; self.max:
                    need_more_photos = False

        return self.get_photos()
</code></pre>
<p>Version 4 is a crazy one. It tries to simulate to goto statement in Python. Everybody will tell you the goto statement is evil and well, most of the times, it is. But sometimes it has no good replacement like this one where we want to stop two nested loops with a statement. Too bad Python does not have a goto statement <img src='http://www.lorenzogil.com/blog/wp-includes/images/smilies/icon_sad.gif' alt=':(' class='wp-smiley' /> </p>
<pre><code>
    def collect_photos4(self, destination):
        n_photos_collected = 0
        try:
            for collector in self.collectors:
                for photo_info in collector(destination):
                    self.add_photo(photo_info)
                    n_photos_collected += 1
                    if n_photos_collected &gt; self.max:
                        raise TypeError('goto')

        except TypeError:
            pass

        return self.get_photos()

</code></pre>
<p>Now, what if we separate the two problems this method is trying to solve: iterating over the photos and adding to our result set. Doing so we can write a simple generator that gives us a photo at a time and then a while loop that check there are more photos in this generator and we actually want them. I like this version more than any of the previous one but still, the while loop is not very readable.</p>
<pre><code>
    def collect_photos5(self, destination):
        def photos_fetcher():
            for collector in self.collectors:
                for photo in collector(destination):
                    yield photo

        n_photos_collected = 0
        photos_iterator = photos_fetcher()
        while n_photos_collected &lt; self.max and photos_iterator.has_next():
            photo_info = photos_iterator.next()
            self.add_photo(photo_info)
            n_photos_collected += 1

        return self.get_photos()
</code></pre>
<p>And then, the last version. I decided to add the stop condition logic into the generator and as it is a nested function I can put a return statement to exit from the two nested loops. Then the main loop can be a for loop without the boilerplate management code that the while loop needed.</p>
<pre><code>
    def collect_photos6(self, destination):
        def photos_fetcher(max_photos):
            n_photos_collected = 0
            for collector in self.collectors:
                for photo in collector(destination):
                    if n_photos_collected &gt; max_photos:
                        return
                    yield photo
                    n_photos_collected += 1

        for photo_info in photos_fetcher(self.max):
            self.add_photo(photo_info)

        return self.get_photos()
</code></pre>
<p>What version do you like most?</p>
]]></content:encoded>
			<wfw:commentRss>http://www.lorenzogil.com/blog/2009/04/19/there-are-more-than-one-way-to-do-it/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Mapping inheritance to a RDBMS with storm. Autoproxy version</title>
		<link>http://www.lorenzogil.com/blog/2009/01/27/mapping-inheritance-to-a-rdbms-with-storm-autoproxy-version/</link>
		<comments>http://www.lorenzogil.com/blog/2009/01/27/mapping-inheritance-to-a-rdbms-with-storm-autoproxy-version/#comments</comments>
		<pubDate>Mon, 26 Jan 2009 23:05:57 +0000</pubDate>
		<dc:creator>lgs</dc:creator>
		
		<category><![CDATA[Ordenadores]]></category>

		<category><![CDATA[zope]]></category>

		<guid isPermaLink="false">http://www.lorenzogil.com/blog/?p=104</guid>
		<description><![CDATA[We saw in the Proxy version that some types of queries were not possible using the lazr.delegates package. We solved that problem using Storm&#8217;s Proxy objects but we lost easyness in the process.
This time we will try to combine both aproaches to get the best of both worlds.
The interface definitions do not change:

   [...]]]></description>
			<content:encoded><![CDATA[<p>We saw in the Proxy version that some types of queries were not possible using the lazr.delegates package. <a href="http://www.lorenzogil.com/blog/2009/01/23/mapping-inheritance-to-a-rdbms-with-storm-proxy-version/">We solved that problem</a> using Storm&#8217;s Proxy objects but we lost easyness in the process.</p>
<p>This time we will try to combine both aproaches to get the best of both worlds.</p>
<p>The interface definitions do not change:</p>
<pre>
    >>> from zope.interface import Interface, Attribute
    >>> class IPerson(Interface):
    ...     name = Attribute("Name")
    ...
    >>> class ISecretAgent(IPerson):
    ...     passcode = Attribute("Passcode")
    ...
    >>> class ITeacher(IPerson):
    ...     school = Attribute("School")
</pre>
<p>Neither the Person class:</p>
<pre>
    >>> from zope.interface import implements
    >>> from zope.interface.verify import verifyClass
    >>> from lazr.delegates import delegates
    >>> from storm.locals import Store, Storm, Unicode, Int, Proxy, Reference
    >>> class Person(Storm):
    ...     implements(IPerson)
    ...
    ...     __storm_table__ = "person"
    ...
    ...     id = Int(allow_none=False, primary=True)
    ...     name = Unicode()
    ...     person_type = Int(allow_none=False)
    ...     _person = None
    ...
    ...     def __init__(self, store, name, person_class, **kwargs):
    ...         self.name = name
    ...         self.person_type = person_class.person_type
    ...         store.add(self)
    ...         self._person = person_class(self, **kwargs)
    ...
    ...     @property
    ...     def person(self):
    ...         if self._person is None:
    ...             assert self.id is not None
    ...             person_class = BasePerson.get_class(self.person_type)
    ...             self._person = Store.of(self).get(person_class, self.id)
    ...         return self._person
    ...
    >>> verifyClass(IPerson, Person)
    True
</pre>
<p>Now, the real magic is in the metaclass. We use it not only to register our subclasses (so the Person.person property can find them) but to automatically store the attributes we needed to set manually in our previous version: the person_id and person attributes and a proxy object for each Person attribute. It&#8217;s like we are reimplementing inheritance in Python but not really <img src='http://www.lorenzogil.com/blog/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<pre>
    >>> from storm.properties import PropertyPublisherMeta
    >>> class PersonType(PropertyPublisherMeta):
    ...     def __init__(self, name, bases, dict):
    ...         if hasattr(self, '__storm_table__'):
    ...             # this need to be done before calling the superclass
    ...             # otherwise Storm will cry about not having a primary key
    ...             self.person_id = Int(allow_none=False, primary=True)
    ...
    ...         super(PersonType, self).__init__(name, bases, dict)
    ...
    ...         if not hasattr(self, '_person_types_registry'):
    ...             self._person_types_registry = {}
    ...         elif hasattr(self, '__storm_table__'):
    ...             key = len(self._person_types_registry)
    ...             self._person_types_registry[key] = self
    ...             self.person_type = key
    ...
    ...             self.person = Reference(self.person_id, Person.id)
    ...             self._add_proxy_properties()
    ...
    ...     def _add_proxy_properties(self):
    ...         for name in IPerson:
    ...             if not hasattr(self, name):
    ...                 remote_attr = getattr(Person, name)
    ...                 setattr(self, name, Proxy(self.person, remote_attr))
    ...
    ...     def get_class(self, person_type):
    ...         return self._person_types_registry[person_type]
</pre>
<p>Not our BasePerson is really simple</p>
<pre>
    >>> class BasePerson(Storm):
    ...     __metaclass__ = PersonType
    ...
    ...     def __init__(self, person):
    ...         self.person = person
</pre>
<p>And so are the subclasses. No repetition, so it is less prone to mistakes <img src='http://www.lorenzogil.com/blog/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<pre>
    >>> class SecretAgent(BasePerson):
    ...     implements(ISecretAgent)
    ...
    ...     __storm_table__ = "secret_agent"
    ...     passcode = Unicode()
    ...
    ...     def __init__(self, person, passcode=None):
    ...         super(SecretAgent, self).__init__(person)
    ...         self.passcode = passcode
    ...
    >>> verifyClass(ISecretAgent, SecretAgent)
    True
    >>> class Teacher(BasePerson):
    ...     implements(ITeacher)
    ...
    ...     __storm_table__ = "teacher"
    ...     school = Unicode()
    ...
    ...     def __init__(self, person, school=None):
    ...         super(Teacher, self).__init__(person)
    ...         self.school = school
    ...
    >>> verifyClass(ITeacher, Teacher)
    True
</pre>
<p>Let&#8217;s make sure our queries work as expected:</p>
<pre>
    >>> from storm.locals import create_database
    >>> database = create_database("sqlite:")
    >>> store = Store(database)
    >>> result = store.execute("""
    ...     CREATE TABLE person (
    ...         id INTEGER PRIMARY KEY,
    ...         person_type INTEGER NOT NULL,
    ...         name TEXT NOT NULL)
    ... """)
    >>> result = store.execute("""
    ...     CREATE TABLE secret_agent (
    ...         person_id INTEGER PRIMARY KEY,
    ...         passcode TEXT)
    ... """)
    >>> result = store.execute("""
    ...     CREATE TABLE teacher (
    ...         person_id INTEGER PRIMARY KEY,
    ...         school TEXT)
    ... """)
    ...
    >>> secret_agent = Person(store, u"James Bond",
    ...                        SecretAgent, passcode=u"007")
    >>> ISecretAgent.providedBy(secret_agent.person)
    True
    >>> teacher = Person(store, u"Albus Dumbledore",
    ...                  Teacher, school=u"Hogwarts")
    >>> ITeacher.providedBy(teacher.person)
    True
    >>> store.commit()
    >>> del secret_agent
    >>> del teacher
    >>> store.rollback()
    >>> secret_agent = store.find(SecretAgent).one()
    >>> secret_agent.name, secret_agent.passcode
    (u'James Bond', u'007')
    >>> teacher = store.find(Teacher).one()
    >>> teacher.name, teacher.school
    (u'Albus Dumbledore', u'Hogwarts')
    >>> secret_agent = store.find(SecretAgent, SecretAgent.name==u'James Bond').one()
    >>> secret_agent.passcode
    u'007'
    >>> teacher = store.find(Teacher, Teacher.school==u'Hogwarts').one()
    >>> teacher.name
    u'Albus Dumbledore'
</pre>
<p>So we made it by using a metaclass that automatically generate a bunch of attributes.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.lorenzogil.com/blog/2009/01/27/mapping-inheritance-to-a-rdbms-with-storm-autoproxy-version/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Mapping inheritance to a RDBMS with storm. Proxy version</title>
		<link>http://www.lorenzogil.com/blog/2009/01/23/mapping-inheritance-to-a-rdbms-with-storm-proxy-version/</link>
		<comments>http://www.lorenzogil.com/blog/2009/01/23/mapping-inheritance-to-a-rdbms-with-storm-proxy-version/#comments</comments>
		<pubDate>Thu, 22 Jan 2009 22:39:16 +0000</pubDate>
		<dc:creator>lgs</dc:creator>
		
		<category><![CDATA[Ordenadores]]></category>

		<category><![CDATA[zope]]></category>

		<guid isPermaLink="false">http://www.lorenzogil.com/blog/?p=97</guid>
		<description><![CDATA[One problem that we had in the first version of our inheritance by composition pattern was that we could not make storm queries using the subclasses. In other words, the following would return None::
    secret_agent = store.find(SecretAgent, SecretAgent.name==u'James Bond').one()
The reason is that the expresion SecretAgent.name would resolve to a Passthrough lazr.delegates object [...]]]></description>
			<content:encoded><![CDATA[<p>One problem that we had in the <a href="http://www.lorenzogil.com/blog/2009/01/18/mapping-inheritance-to-a-rdbms-with-storm-and-lazrdelegates/" target="_self">first version</a> of our inheritance by composition pattern was that we could not make storm queries using the subclasses. In other words, the following would return None::</p>
<pre>    secret_agent = store.find(SecretAgent, SecretAgent.name==u'James Bond').one()</pre>
<p>The reason is that the expresion SecretAgent.name would resolve to a Passthrough lazr.delegates object that Storm does not know how to handle.</p>
<p>This time we will try to fix this problem using a manually generated version of our classes using storm&#8217;s Proxy objects.</p>
<p>The interface definitions do not change:</p>
<pre>    &gt;&gt;&gt; from zope.interface import Interface, Attribute
    &gt;&gt;&gt; class IPerson(Interface):
    ...     name = Attribute("Name")
    ...
    &gt;&gt;&gt; class ISecretAgent(IPerson):
    ...     passcode = Attribute("Passcode")
    ...
    &gt;&gt;&gt; class ITeacher(IPerson):
    ...     school = Attribute("School")</pre>
<p>Neither the Person class:</p>
<pre>    &gt;&gt;&gt; from zope.interface import implements
    &gt;&gt;&gt; from zope.interface.verify import verifyClass
    &gt;&gt;&gt; from lazr.delegates import delegates
    &gt;&gt;&gt; from storm.locals import Store, Storm, Unicode, Int, Proxy, Reference
    &gt;&gt;&gt; class Person(Storm):
    ...     implements(IPerson)
    ...
    ...     __storm_table__ = "person"
    ...
    ...     id = Int(allow_none=False, primary=True)
    ...     name = Unicode()
    ...     person_type = Int(allow_none=False)
    ...     _person = None
    ...
    ...     def __init__(self, store, name, person_class, **kwargs):
    ...         self.name = name
    ...         self.person_type = person_class.person_type
    ...         store.add(self)
    ...         self._person = person_class(self, **kwargs)
    ...
    ...     @property
    ...     def person(self):
    ...         if self._person is None:
    ...             assert self.id is not None
    ...             person_class = BasePerson.get_class(self.person_type)
    ...             self._person = Store.of(self).get(person_class, self.id)
    ...         return self._person
    &gt;&gt;&gt; verifyClass(IPerson, Person)
    True</pre>
<p>Neither our custom metaclass:</p>
<pre>    &gt;&gt;&gt; from storm.properties import PropertyPublisherMeta
    &gt;&gt;&gt; class PersonType(PropertyPublisherMeta):
    ...     def __init__(self, name, bases, dict):
    ...         super(PersonType, self).__init__(name, bases, dict)
    ...         if not hasattr(self, '_person_types_registry'):
    ...             self._person_types_registry = {}
    ...         elif hasattr(self, '__storm_table__'):
    ...             key = len(self._person_types_registry)
    ...             self._person_types_registry[key] = self
    ...             self.person_type = key
    ...
    ...     def get_class(self, person_type):
    ...         return self._person_types_registry[person_type]</pre>
<p>Here start the changes. Our BasePerson class does not have the delegates call and does not define the person_id attribute and person reference.</p>
<pre>    &gt;&gt;&gt; class BasePerson(Storm):
    ...     __metaclass__ = PersonType
    ...
    ...     def __init__(self, person):
    ...         self.person = person</pre>
<p>Instead we define the person_id and person reference in each subclass and also we define each attribute of the Person base class as a proxy to the related attribute of the person reference.</p>
<pre>    &gt;&gt;&gt; class SecretAgent(BasePerson):
    ...     implements(ISecretAgent)
    ...
    ...     __storm_table__ = "secret_agent"
    ...     passcode = Unicode()
    ...     person_id = Int(allow_none=False, primary=True)
    ...     person = Reference(person_id, Person.id)
    ...     name = Proxy(person, Person.name)
    ...
    ...     def __init__(self, person, passcode=None):
    ...         super(SecretAgent, self).__init__(person)
    ...         self.passcode = passcode
    &gt;&gt;&gt; verifyClass(ISecretAgent, SecretAgent)
    True</pre>
<p>We do it again for the Teacher class:</p>
<pre>    &gt;&gt;&gt; class Teacher(BasePerson):
    ...     implements(ITeacher)
    ...
    ...     __storm_table__ = "teacher"
    ...     school = Unicode()
    ...     person_id = Int(allow_none=False, primary=True)
    ...     person = Reference(person_id, Person.id)
    ...     name = Proxy(person, Person.name)
    ...
    ...     def __init__(self, person, school=None):
    ...         super(Teacher, self).__init__(person)
    ...         self.school = school
    &gt;&gt;&gt; verifyClass(ITeacher, Teacher)
    True</pre>
<p>Time to test the database storage:</p>
<pre>    &gt;&gt;&gt; from storm.locals import create_database
    &gt;&gt;&gt; database = create_database("sqlite:")
    &gt;&gt;&gt; store = Store(database)
    &gt;&gt;&gt; result = store.execute("""
    ...     CREATE TABLE person (
    ...         id INTEGER PRIMARY KEY,
    ...         person_type INTEGER NOT NULL,
    ...         name TEXT NOT NULL)
    ... """)
    &gt;&gt;&gt; result = store.execute("""
    ...     CREATE TABLE secret_agent (
    ...         person_id INTEGER PRIMARY KEY,
    ...         passcode TEXT)
    ... """)
    &gt;&gt;&gt; result = store.execute("""
    ...     CREATE TABLE teacher (
    ...         person_id INTEGER PRIMARY KEY,
    ...         school TEXT)
    ... """)
    &gt;&gt;&gt; secret_agent = Person(store, u"James Bond",
    ...                        SecretAgent, passcode=u"007")
    &gt;&gt;&gt; ISecretAgent.providedBy(secret_agent.person)
    True
    &gt;&gt;&gt; teacher = Person(store, u"Albus Dumbledore",
    ...                  Teacher, school=u"Hogwarts")
    &gt;&gt;&gt; ITeacher.providedBy(teacher.person)
    True
    &gt;&gt;&gt; store.commit()</pre>
<p>And what&#8217;s more important, all this changes should make possible to do the query with the subclass:</p>
<pre>    &gt;&gt;&gt; del secret_agent
    &gt;&gt;&gt; del teacher
    &gt;&gt;&gt; store.rollback()
    &gt;&gt;&gt; secret_agent = store.find(SecretAgent).one()
    &gt;&gt;&gt; secret_agent.name, secret_agent.passcode
    (u'James Bond', u'007')
    &gt;&gt;&gt; teacher = store.find(Teacher).one()
    &gt;&gt;&gt; teacher.name, teacher.school
    (u'Albus Dumbledore', u'Hogwarts')
    &gt;&gt;&gt; secret_agent = store.find(SecretAgent, SecretAgent.name==u'James Bond').one()
    &gt;&gt;&gt; secret_agent.passcode
    u'007'</pre>
<p>We have improved the power of the pattern but now it is much more verbose to write each subclass since we need to repeat a lot of things. Note that we can not move the definition of the person_id and person attributes to the BasePerson aux class because Storm will tell us that it lacks the __storm_table__ attribute. In other words: storm does not allow attributes in abstract classes.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.lorenzogil.com/blog/2009/01/23/mapping-inheritance-to-a-rdbms-with-storm-proxy-version/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Mapping inheritance to a RDBMS with storm and lazr.delegates</title>
		<link>http://www.lorenzogil.com/blog/2009/01/18/mapping-inheritance-to-a-rdbms-with-storm-and-lazrdelegates/</link>
		<comments>http://www.lorenzogil.com/blog/2009/01/18/mapping-inheritance-to-a-rdbms-with-storm-and-lazrdelegates/#comments</comments>
		<pubDate>Sun, 18 Jan 2009 09:26:54 +0000</pubDate>
		<dc:creator>lgs</dc:creator>
		
		<category><![CDATA[Ordenadores]]></category>

		<category><![CDATA[zope]]></category>

		<guid isPermaLink="false">http://www.lorenzogil.com/blog/?p=78</guid>
		<description><![CDATA[When using a ORM one of the most common problems is how to map your beautiful
application class inheritance to the database. The specific scenario I&#8217;m going
to describe is when you have an abstract base class with some fields and you
want to store those fields in a database table. Then all of its subclasses will
have their [...]]]></description>
			<content:encoded><![CDATA[<p>When using a ORM one of the most common problems is how to map your beautiful<br />
application class inheritance to the database. The specific scenario I&#8217;m going<br />
to describe is when you have an abstract base class with some fields and you<br />
want to store those fields in a database table. Then all of its subclasses will<br />
have their own table and to get the data of an instance you will need to make<br />
a join between the base table and the subclass table.</p>
<p>One pattern to accomplish this is the infoheritance pattern described in the<br />
<a href="https://storm.canonical.com/" target="_self">Storm documentation</a>. I&#8217;ll show you here a slightly modified version of this<br />
pattern that uses the package <a href="http://pypi.python.org/pypi/lazr.delegates" target="_self">lazr.delegates</a> to make the user code easier by<br />
hiding the fact that we are using composition to model inheritance.</p>
<p>So let&#8217;s start with some interface definition showing our model hierarchy:</p>
<p><code> </code></p>
<pre>    &gt;&gt;&gt; from zope.interface import Interface, Attribute
    &gt;&gt;&gt; class IPerson(Interface):
    ...     name = Attribute("Name")
    ...
    &gt;&gt;&gt; class ISecretAgent(IPerson):
    ...     passcode = Attribute("Passcode")
    ...
    &gt;&gt;&gt; class ITeacher(IPerson):
    ...     school = Attribute("School")</pre>
<p>No rocket science so far. Let&#8217;s write now the implementation of the<br />
IPerson interface. This will be our abstract base class. Pay special<br />
attention to the person property which dynamically retrieve the subclass<br />
instance by using composition.</p>
<p><code> </code></p>
<pre>    &gt;&gt;&gt; from zope.interface import implements
    &gt;&gt;&gt; from zope.interface.verify import verifyClass
    &gt;&gt;&gt; from lazr.delegates import delegates
    &gt;&gt;&gt; from storm.locals import Store, Storm, Unicode, Int, Reference
    &gt;&gt;&gt; class Person(Storm):
    ...     implements(IPerson)
    ...
    ...     __storm_table__ = "person"
    ...
    ...     id = Int(allow_none=False, primary=True)
    ...     name = Unicode()
    ...     person_type = Int(allow_none=False)
    ...     _person = None
    ...
    ...     def __init__(self, store, name, person_class, **kwargs):
    ...         self.name = name
    ...         self.person_type = person_class.person_type
    ...         store.add(self)
    ...         self._person = person_class(self, **kwargs)
    ...
    ...     @property
    ...     def person(self):
    ...         if self._person is None:
    ...             assert self.id is not None
    ...             person_class = BasePerson.get_class(self.person_type)
    ...             self._person = Store.of(self).get(person_class, self.id)
    ...         return self._person
    &gt;&gt;&gt; verifyClass(IPerson, Person)
    True</pre>
<p>We will also use a custom metaclass (based on Storm metaclass) so it will<br />
automatically register our subclasses. This is necessary for the dynamic<br />
person property of the Person class where we map integer (stored in the<br />
database) to classes (stored in the source code).</p>
<p><code> </code></p>
<pre>    &gt;&gt;&gt; from storm.properties import PropertyPublisherMeta
    &gt;&gt;&gt; class PersonType(PropertyPublisherMeta):
    ...     def __init__(self, name, bases, dict):
    ...         super(PersonType, self).__init__(name, bases, dict)
    ...         if not hasattr(self, '_person_types_registry'):
    ...             self._person_types_registry = {}
    ...         elif hasattr(self, '__storm_table__'):
    ...             key = len(self._person_types_registry)
    ...             self._person_types_registry[key] = self
    ...             self.person_type = key
    ...
    ...     def get_class(self, person_type):
    ...         return self._person_types_registry[person_type]</pre>
<p>Now we define a convenience base class for our subclasses. Remember that<br />
the subclasses don&#8217;t really inherit from the Person class  because we<br />
are using composition. This is where the lazr.delegates.delegates function<br />
comes to rescue. By saying that we delegate the implementation of the<br />
IPerson interface to the &#8216;person&#8217; attribute, the instances of these subclasses<br />
will look like they really are subclasses of Person, not just from BasePerson.</p>
<p><code> </code></p>
<pre>    &gt;&gt;&gt; class BasePerson(Storm):
    ...     __metaclass__ = PersonType
    ...     delegates(IPerson, "person")
    ...
    ...     person_id = Int(allow_none=False, primary=True)
    ...     person = Reference(person_id, "Person.id")
    ...
    ...     def __init__(self, person):
    ...         self.person = person
    ...
    &gt;&gt;&gt; class SecretAgent(BasePerson):
    ...     implements(ISecretAgent)
    ...
    ...     __storm_table__ = "secret_agent"
    ...     passcode = Unicode()
    ...
    ...     def __init__(self, person, passcode=None):
    ...         super(SecretAgent, self).__init__(person)
    ...         self.passcode = passcode</pre>
<p>Here is the magic: we have an interface hierarchy and a different<br />
hierarchy for the classes implementing them. But it&#8217;s all transparent<br />
and our classes implement the full hierarchy:</p>
<p><code> </code></p>
<pre>    &gt;&gt;&gt; verifyClass(ISecretAgent, SecretAgent)
    True
    &gt;&gt;&gt; class Teacher(BasePerson):
    ...     implements(ITeacher)
    ...
    ...     __storm_table__ = "teacher"
    ...     school = Unicode()
    ...
    ...     def __init__(self, person, school=None):
    ...         super(Teacher, self).__init__(person)
    ...         self.school = school
    ...
    &gt;&gt;&gt; verifyClass(ITeacher, Teacher)
    True</pre>
<p>Now let&#8217;s try storing the objects in the database. We will use a<br />
sqlite in memory database for this example.</p>
<p><code> </code></p>
<pre>    &gt;&gt;&gt; from storm.locals import create_database
    &gt;&gt;&gt; database = create_database("sqlite:")
    &gt;&gt;&gt; store = Store(database)
    &gt;&gt;&gt; result = store.execute("""
    ...     CREATE TABLE person (
    ...         id INTEGER PRIMARY KEY,
    ...         person_type INTEGER NOT NULL,
    ...         name TEXT NOT NULL)
    ... """)
    &gt;&gt;&gt; result = store.execute("""
    ...     CREATE TABLE secret_agent (
    ...         person_id INTEGER PRIMARY KEY,
    ...         passcode TEXT)
    ... """)
    &gt;&gt;&gt; result = store.execute("""
    ...     CREATE TABLE teacher (
    ...         person_id INTEGER PRIMARY KEY,
    ...         school TEXT)
    ... """)
    &gt;&gt;&gt; secret_agent = Person(store, u"James Bond",
    ...                        SecretAgent, passcode=u"007")
    &gt;&gt;&gt; ISecretAgent.providedBy(secret_agent.person)
    True
    &gt;&gt;&gt; teacher = Person(store, u"Albus Dumbledore",
    ...                  Teacher, school=u"Hogwarts")
    &gt;&gt;&gt; ITeacher.providedBy(teacher.person)
    True
    &gt;&gt;&gt; store.commit()</pre>
<p>The objects are now saved in the database. Let&#8217;s destroy them and<br />
retrieve them back using some queries:</p>
<p><code> </code></p>
<pre>    &gt;&gt;&gt; del secret_agent
    &gt;&gt;&gt; del teacher
    &gt;&gt;&gt; store.rollback()
    &gt;&gt;&gt; secret_agent = store.find(SecretAgent).one()
    &gt;&gt;&gt; secret_agent.name, secret_agent.passcode
    (u'James Bond', u'007')
    &gt;&gt;&gt; teacher = store.find(Teacher).one()
    &gt;&gt;&gt; teacher.name, teacher.school
    (u'Albus Dumbledore', u'Hogwarts')</pre>
<p>The great thing is that we can write teacher.name without having to<br />
write teacher.person.name (which also works by the way) effectively<br />
hiding the implementation detail of composition.</p>
<p>Just one final note: Bear in mind that you should not have very deep<br />
hierarchies or you may get a lot of JOINs and a slow application.</p>
<p>You can download a couple of files to test this on your own computer. You just need storm 0.14 and lazr.delegates 1.0, both of which can be installed with easy_install:</p>
<ul>
<li><a href="http://www.lorenzogil.com/blog/wp-content/uploads/2009/01/inheritance.txt">Doctests</a></li>
<li><a href="http://www.lorenzogil.com/blog/wp-content/uploads/2009/01/tests.py"></a><a href="http://www.lorenzogil.com/blog/wp-content/uploads/2009/01/tests.py">Test runner</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.lorenzogil.com/blog/2009/01/18/mapping-inheritance-to-a-rdbms-with-storm-and-lazrdelegates/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Conexión a internet desde un móvil Nokia 6234 con Simyo</title>
		<link>http://www.lorenzogil.com/blog/2008/12/14/conexion-a-internet-desde-un-movil-nokia-6234-con-simyo/</link>
		<comments>http://www.lorenzogil.com/blog/2008/12/14/conexion-a-internet-desde-un-movil-nokia-6234-con-simyo/#comments</comments>
		<pubDate>Sun, 14 Dec 2008 10:25:13 +0000</pubDate>
		<dc:creator>lgs</dc:creator>
		
		<category><![CDATA[Ordenadores]]></category>

		<category><![CDATA[Tiendas]]></category>

		<category><![CDATA[Yaco]]></category>

		<category><![CDATA[internet]]></category>

		<category><![CDATA[simyo]]></category>

		<guid isPermaLink="false">http://www.lorenzogil.com/blog/?p=66</guid>
		<description><![CDATA[Tras un par de intentos fallidos de conectarme a Internet desde mi móvil con mi nuevo proveedor he conseguido que funcione.
A continuación escribo las opciones que he tenido que configurar en el móvil para conseguirlo. Espero que la nomenclatura se entienda.
Configuración: Configuración: Ajustes config. personal: Opciones: Añadir nuevo: Internet

  Nombre de cuenta: Internet Simyo
 [...]]]></description>
			<content:encoded><![CDATA[<p>Tras un par de intentos fallidos de conectarme a Internet desde mi móvil con <a title="Simyo" href="http://www.simyo.es" target="_self">mi nuevo proveedor</a> he conseguido que funcione.</p>
<div id="attachment_71" class="wp-caption aligncenter" style="width: 310px"><img class="size-full wp-image-71" title="nokia-6234" src="http://www.lorenzogil.com/blog/wp-content/uploads/2008/12/nokia-6234.jpg" alt="Nokia 6234" width="300" height="325" /><p class="wp-caption-text">Nokia 6234</p></div>
<p>A continuación escribo las opciones que he tenido que configurar en el móvil para conseguirlo. Espero que la nomenclatura se entienda.</p>
<pre>Configuración: Configuración: Ajustes config. personal: Opciones: Añadir nuevo: Internet

  Nombre de cuenta: Internet Simyo
  Página de inicio: http://www.google.com
  Nombre de usuario:
  Contraseña:
  Usar pto. acceso preferido: No
  Conf. de punto de acceso:

    Proxy: Activado
    Dirección de proxy: 217.18.32.181
    Puerto de proxy: 8080
    Portador de datos: Paquetes de datos
    Configuración portador:

      Pto. acceso paquts. datos: gprs-service.com
      Tipo de red: IPv4
      Tipo de autentificación: Normal
      Nombre de usuario:
      Contraseña: 

Internet: Configuración: Ajustes de configuración:

  Configuración: Configuración personal
  Cuenta: Internet Simyo
  Mostrar ventana terminal: No</pre>
<p>Para el que esté pensando que eso de internet desde un móvil normalito no tiene mucho sentido pues sí y no. Está claro que cualquier parecido entre navegar con un ordenador y un móvil como el mío es pura coincidencia, pero eso no quiere decir que la posibilidad de ver tu correo en Gmail desde tu móvil no sea útil o también, la posibilidad de sincronizar tus contactos entre el móvil, el ordenador, tu cuenta google, etc. usando servicios como <a href="http://www.scheduleworld.com/" target="_self">scheduleworld.com</a></p>
<p>Las tarifas de mi proveedor las podeis consultar <a title="Simyo Internet" href="http://www.simyo.es/internet/" target="_self">en su web</a> y la verdad es que me parecen bastante razonables. Por ahora estoy contento con <a title="Simyo" href="http://www.simyo.es" target="_self">Simyo</a> no sólo por que me resulta más barato que mi anterior proveedor, si no porque es infinitamente más transparente y claro que los demás y al menos tienes la sensación de que estás pagando por lo que usas, no por lo que ellos quieren.</p>
<p>El siguiente paso ha sido conectar mi Nokia N800 al teléfono vía Bluetooth y usar la conexión a internet del teléfono para navegar desde el otro cacharro. Esto ya se va pareciendo mucho más a navegar a la vieja usanza gracias a la pantalla de 800 pixeles de ancho que tiene el N800.</p>
<div id="attachment_73" class="wp-caption aligncenter" style="width: 470px"><a href="http://www.lorenzogil.com/blog/wp-content/uploads/2008/12/nokian800.jpg"><img class="size-medium wp-image-73" title="nokian800" src="http://www.lorenzogil.com/blog/wp-content/uploads/2008/12/nokian800.jpg" alt="Nokia N800" width="460" height="322" /></a><p class="wp-caption-text">Nokia N800</p></div>
<p>Si mi portátil tuviera Bluetooth, también podría conectarme a internet desde cualquier sitio, pero fui tan listo al comprarlo que desactive esa opción pensando que nunca la usaría. Ahora puedo pedir esa ampliación e instalarla yo mismo o comprar un pequeño dongle usb y hacer lo mismo.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.lorenzogil.com/blog/2008/12/14/conexion-a-internet-desde-un-movil-nokia-6234-con-simyo/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Encoding videos for the Nokia N800</title>
		<link>http://www.lorenzogil.com/blog/2008/11/23/encoding-videos-for-the-nokia-n800/</link>
		<comments>http://www.lorenzogil.com/blog/2008/11/23/encoding-videos-for-the-nokia-n800/#comments</comments>
		<pubDate>Sun, 23 Nov 2008 13:13:16 +0000</pubDate>
		<dc:creator>lgs</dc:creator>
		
		<category><![CDATA[Ordenadores]]></category>

		<guid isPermaLink="false">http://www.lorenzogil.com/blog/?p=58</guid>
		<description><![CDATA[Quick command reminder about how to encode videos for watching them in the Nokia N800:
mencoder Fringe-S01E06.avi -o Fringe-S01E06-n800.avi -oac mp3lame -lavcopts acodec=libmp3lame:abitrate=96 -ovc lavc -lavcopts vcodec=mpeg4:autoaspect:vbitrate=600:vpass=1:turbo -vf scale=400:240 -ffourcc DIVX -idx
Update: add these options to embed subtitles:
-sub Fringe-S01E06.srt -subcp latin5 -subfont-text-scale 4
You will need a subfont.ttf font file in ~/.mplayer/
]]></description>
			<content:encoded><![CDATA[<p>Quick command reminder about how to encode videos for watching them in the Nokia N800:</p>
<pre>mencoder Fringe-S01E06.avi -o Fringe-S01E06-n800.avi -oac mp3lame -lavcopts acodec=libmp3lame:abitrate=96 -ovc lavc -lavcopts vcodec=mpeg4:autoaspect:vbitrate=600:vpass=1:turbo -vf scale=400:240 -ffourcc DIVX -idx</pre>
<p>Update: add these options to embed subtitles:</p>
<pre>-sub Fringe-S01E06.srt -subcp latin5 -subfont-text-scale 4</pre>
<p>You will need a subfont.ttf font file in ~/.mplayer/</p>
]]></content:encoded>
			<wfw:commentRss>http://www.lorenzogil.com/blog/2008/11/23/encoding-videos-for-the-nokia-n800/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Viajes y cambios</title>
		<link>http://www.lorenzogil.com/blog/2008/09/13/viajes-y-cambios/</link>
		<comments>http://www.lorenzogil.com/blog/2008/09/13/viajes-y-cambios/#comments</comments>
		<pubDate>Sat, 13 Sep 2008 08:32:44 +0000</pubDate>
		<dc:creator>lgs</dc:creator>
		
		<category><![CDATA[Amigos]]></category>

		<category><![CDATA[Viajes]]></category>

		<guid isPermaLink="false">http://www.lorenzogil.com/blog/?p=57</guid>
		<description><![CDATA[Este mes de Agosto Ana y yo fuimos a Londres. Ana nunca había estado antes y aunque yo había estado en algunas ocasiones, Londres es de esas ciudades en las que es totalmente imposible aburrirse o decir &#8220;es que ya he visto todo lo que había que ver&#8221;. Así que nos metimos en EasyJet un [...]]]></description>
			<content:encoded><![CDATA[<p>Este mes de Agosto <a href="http://anita.moralesdelcastillo.com/blog/" target="_self">Ana</a> y yo fuimos a Londres. Ana nunca había estado antes y aunque yo había estado en algunas ocasiones, Londres es de esas ciudades en las que es totalmente imposible aburrirse o decir &#8220;es que ya he visto todo lo que había que ver&#8221;. Así que nos metimos en EasyJet un Lunes por la mañana y aparecimos en Gatwick poco rato después. Vaya tela el Gatwick Express: sesenta y tantas libras por dos billetes ida y vuelta.</p>
<p><img src="http://farm4.static.flickr.com/3168/2847952737_03c6fb58c0.jpg" alt="Loren delante de las Casas del Parlamento" width="500" height="375" /></p>
<p>Nota para posibles visitantes a Londres: im-pres-cin-di-ble la Oyster card para viajar por el metro. Sale muchísimo más barata que ir a pagando a pelo y luego está el efecto molón de ir pasando la cartera por los lectores de tarjetas sin necesidad de sacar la tarjeta. Al final le cogimos el truco y parecíamos londinenses, bueno eso de cuello para abajo, de cuello para arriba era muy difícil ocultar que en realidad somos de londonelzaidin ya que la cara de empanaos y turistas la llevamos a todas partes. Igual que Dos Flores.</p>
<p><img src="http://farm4.static.flickr.com/3164/2848712234_37894838b5.jpg" alt="Anita en el momento británico" width="500" height="375" /></p>
<p>De las cosas que vimos, que no fueron pocas (a Ana incluso se le rompieron los zapatos de tanto andar) nos quedamos sin duda con el museo de Historia Natural. Impresionante tanto el continente como el contenido. No tan popular como la Tate o el Museo Británico pero para flipaos de los bichos como nosotros igual o más interesante.</p>
<p><img src="http://farm4.static.flickr.com/3066/2848712208_fd0b5ae94c.jpg" alt="Tripu y Loren" width="500" height="375" /></p>
<p>Mención especial de nuestro viaje fue el encuentro con nuestro más querido <a href="http://blog.tripu.info/" target="_self">Tripulante</a>, que hizo de anfitrión excepcional y nos enseño todo el Soho (el barrio) mostrándonos tanto los sitios más típicos como algunos restaurantes con las tres bes. Un día toco italiano y otro día griego. Muy mediterráneo, sí, pero mejor no preguntéis por la comida inglesa: es casi inexistente si la buscas en restaurantes y por algo será.</p>
<p><img src="http://farm4.static.flickr.com/3003/2848712224_a6bdf1af48.jpg" alt="Se acaba la diversión" width="375" height="500" /></p>
<p>En fín, un viaje muy típico pero también muy recomendable. Si aún no has estado en Londres, no tienes excusa ahora que está a tiro de piedra con compañias low cost. Más fotos en el <a href="http://www.flickr.com/photos/14508827@N00/2847952749/" target="_self">Flickr de Ana</a>.</p>
<p>También han sido mis vacaciones más largas desde que empecé en <a href="http://www.sicem.biz" target="_self">Sicem</a> haya por el 2003. Quince días de vacaciones y quince en paro. El lunes empiezo en <a href="http://www.yaco.es" target="_self">Yaco</a> y la verdad, tengo bastantes ganas de empezar y cambiar un poco de aires.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.lorenzogil.com/blog/2008/09/13/viajes-y-cambios/feed/</wfw:commentRss>
		</item>
	</channel>
</rss>
