jueves, diciembre 06, 2007

Patrones para UIs


Siempre que oímos de patrones, recordamos los patrones de Gamma y cia. Existen muchos otros (los programadores Java no puedan mantener una conversación sobre su lenguaje sin hacer referencia a ellos), pero que pasa con la UI de nuestras aplicaciones web? Existen patrones para la interfase de usuario? Por supuesto, esta es una web que una buena recopilación http://www.welie.com/patterns/index.php

miércoles, noviembre 21, 2007

Mercurial

Hace un tiempo que vengo usando subversion para matener los proysctos propios (siempre regañé de la incomodidad del setup para el uso personal) y la necesidad de cierta disciplina a la hora de hacer commit. Yo soy un programador de rachas, es decir, existen momentos creativos, y momentos de crítica. Generalmente, cuando me ilumino, hago un commit como medida preventiva si rompo todo :S (para que voy a branchear si estoy trabajando solo). Cuando hago lo mismo trabajando en grupo, es decir ser commit friendly... a veces, se entretejen mis commits, con los de otro programador con su "racha creativa", y se llega a un estado que se puede describir con estas palabras: "perá, no hagas commit", "dale, dale, ahora hacé commit", y cosas así...
Comencé a probar otros mecanismos de control de versiones. Probé Svk y Darcs, Bazaar(muy superficialmente, me parecía que estaba demaciado enfocado al desarrollo de Ubuntu) y finalmente encontré algo sencillo, su nombre es mercurial (aka hg). Sinceramente, no fue por el tema de nuestro proceso caótico de desarrollo, sino por que la máquina donde teníamos nuestro server de svn con apache, estaba alejada geográficamente, y nos conectabamos por vpn, y a veces el enlace no funcionaba.

La documentación oficial es corta, sin embargo suficiente.
La principal diferencia entre un sistema de control distribuido, es que uno hace los commits contra su propio repositorio, luego hace push o pull de sus cambios, hacia o desde otro repositorio respectivamente.
Cada copiad de trabajo, es una rama. Si usamos repositorio central, convergerán en el producto final, pero mientras tanto, podemos mantener localmente las versiones. Debido ha esto aumenta la posibilidad de hacer el merge un poco más caótico, pero creo que estar consiente de esto. Si sospecho que alguien en mi equipo de trabajo puede estar introduciendo cambios que pueden hacer que mi merge contra el repo central sea una odisea, puedo hacer un pull del repo de esta persona y ver como remediar el problema.

El setup para http es bastante sencillo, corre como cgi, es cuestion de una regla para mod_rewrite y un location si queremos tener login.
Otra coasa que no probé pero sonó muy bien, es que es plugineable.

Bien, como se usa?
Primero lo instalamos, apt-get install mercurial, emerge mercurial o yum install mercurial (según usemos Debian/Ubuntu, Gentoo o Fedora).
Para crear el repo, en una carpeta:
$ hg init
ahora, si lo que queremos es hacer un "checkout", sería algo como
$ hg clone http://repo # También podemos enviar los cambios por mail o por ssh
cuando queremos hacer commit (muy similar a svn)
$ hg commit
los rollbacks
$ hg rollback
para enviar los cambios
$ hg push
y para traerlos
$ hg pull
Toda la configuración está en la carpeta oculta .hg en el archivo hgrc (.hg/hgrc)
Los archivos que queremos hacer pasar por lato, los ponemos en un .hgignore en el root del proyecto.
Para servir el proyecto por http, adivinen, hg serve, jeje, para quienes usaron subversion la sintaxis es muy similar en muchos comandos, y para quienes no, creo que es bastante sencillo.

Tiene un plugin para trac, que todavía no probé, pero también es otra feature.

lunes, noviembre 12, 2007

Creación de screencasts

Una imagen vale más que mil palabras, y un video?
La wikipedia define un screencast como:
"Un screencast es una grabación digital de la salida por pantalla de la computadora, a veces conteniendo narración de audio."

Existe bastante software para crear screencasts, en Windows, uno muy popular es Camtasia. En el mundo GNU, existen varias posibilidades, pero solo les voy a hablar de las que me parecen maś apropiadas.
Para capturar el video, la mejor aplicación IMHO es Record-My-Desktop, con su idonea interfase Gtk-Record-My-Desktop. Para instalarlo en Ubuntu:
$ sudo apt-get install gtk-recordmydesktop
La aplicación es muy intuitiva, y la captura no consume tanto CPU como ffmpeg. Los resultados son más que aceptables.

La salida de esta aplicación es un archivo out.ogg en nuestro directorio home, que podremos ver sin problemas con vlc, mplayer (les recomiendo la GUI smplayer) o xine.
Siempre graben 5 segundos más de screencast al final, para que no se les certe el video si los keyframes estan muy lejos.
El problema de este formato OGG/Theora, es que ocupa mucho espacio. Para reducir el espacio, podemos recodificar el video utilizando otra aplicación llamada Avidemux que nos brinda una variedad de codecs interesante.
$ sudo apt-get install avidemux
Avidemux no abre directamente los archivos generados por record-my-desktop, debemos convertirlos a algo que el entienda. Para esto podemos utilizar mencoder.
Para instalar mencoder
$ sudo apt-get install mencoder
y para convertir los videos, desde una consola (que podemos lanzar con F4 en Konqueror), ejecutamos la siguiente linea:
$ mencoder OUT.OGG -o SALIDA.AVI -ovc lavc -oac mp3lame
El archivo SALIDA.AVI puede ser leido sin problemas por avidemux. Tengan en cuenta que si hacen varias grabaciones con record-my-desktop, serán numeradas como out.ogg, out.ogg.1, out.ogg.2, etc.
Una vez cargado el archivo en Avidemux, vamos a configurar el codec de video:
H264 es uno de los codecs más avanzados que probé, produce las mejores relaciones peso/calidad, y no trae muchos problemas a la hora de reproducir los archivos.
A la hora de configurar la tasa de bits y las pasadas existen varias alternativas, pero les recomiendo la de elección de tamaño de archivo. Recuerden que si van a enviar el video por mail, el máximo tamaño de attachment es generalmente 10MBs. En lo posible es mejor no acercarse, a menos que nuestros videos alcancen los 20-30 minutos.
Además del codec de video, podemos aplicar varios filtros, uno útil, es el resizer, esto nos puede ahorrar varios bits :)

Finalmente, si nuestro screencast tiene audio, debemos elegir el codec de audio.
Notarán que no existe ningún botón de "Comenzar" o "Convertir" , para iniciar la conversión, tenemos que ir al menú Archvio > "Añadir a la lista de tareas", poniendo el nombre de la tarea y el nombre del archivo destino. Luego con "Archivo" > "Mostar Lista de Tareas" o Ctrl + J, seleccionamos la tarea y la ejecutamos.

Tengan en cuenta que la barra de progreso debe llenarse dos veces si eligieron una codificación de video de dos pasadas (casi siempre).

Espero que les sirva!

viernes, noviembre 09, 2007

Reflexiones de primera semana

Hoy se cumple la primera semana en el laburo de la Uni. Todo ha ido bastante tranquilo. Me aguarda una gran tarea, la de migrar MDeamon a Postfix/Fetchmail o lo que más convega. Control de tráfico también será una de las tareas a tener en cuenta...
En este ultimo tiempo también he estado trabajando bastante con Django, en un trabajo para una intranet. Aprendí que no hay punto de comparación entre un lenguaje dinámico y uno estático (tipado). Salieron cosas genéricas para generar formularios, para generar búsquedas, listados, cosas que espero podamos liberar cuando estén más maduras. Hoy, cuando la primera entrega se encuentra hecha, veo que necesitamos mejorar el proceso, más que el producto. Los lenguajes ya son lo suficientemente sofisticados, los frameworks, los tenemos en todos los colores y sabores, pero cuando el desarrollo se extiende a más de una persona, el proceso de desarrollo es el principal responsable de las demoras y fallas. Ya se, son las palabras de las materias de ingeniería de software, pero, jejeje, voy a refrescar uno de los dichos de uno de mis profes "si escucho, olvido; si leo, recuerdo; si hago, aprendo"

lunes, octubre 22, 2007

Chau FAT32!

Finalmente me he deshecho de una espina que venía molestando desde hace mucho, una partición FAT32 de 91GB.
La operación se realizó sin mayores inconvenientes. Agregué el disco para hacer el almacenamiento temporal. Gracias a que Kubuntu trabaja con UUIDs en vez de dispositivos en fstab, no hubo mayores dramas a la hora del montaje.
Luego de copiar todos los archivos, desde la fat a la ext3 del disco temporal, había transcurrido casi una hora, en la que se portó bastante bien.
Paso siguiente a la copia fue eliminar la platición con cfdisk.
Tuve que hacer export LANG="C", para que dejara de pedirme el molesto acento, en al confirmación de si realmente estaba seguro de escribir la tabla de particiones.
El sistema de archivos elegido fue XFS al cual ya había convertido otra partición con mucha documentación. mkfs.ext3 /dev/sdb8 hizo el trabajo de el formateo en menos de un segundo... pero la copia de archivos tardó una hora más...
Luego de editar fstab, y montar la paritción, inicié Amarok, y no hizo falta hacer nada especial, la colección estaba intacta, con el adicional de carga más veloz de los temas.
Todo un éxito.


martes, octubre 16, 2007

Wine Reviews

Encontré este blog con detallados pasos de instalación de aplicaciones de Windows en Linux mediante Wine.
Contiene información detallada, enumerando las características que funcionan y las que no.
Vale la pena darse una vuelta.

martes, octubre 09, 2007

Kernel 2.6.23

Ya salió el flamante kernel 2.6.23 con muchas novedades. El nuevo scheduler y varios mecanismos de virtualización ya integrados. Actualmente con el kernel patcheado con el último parche de Kolivas, vmware-server no quiere saber nada. Así que vamos a probar que tal le va a este Ubuntu (con sus días como 7.04 contados) con este nuevo núcleo.
Acá les dejo un párrafito de OSNews:

This version includes the new and shiny CFS process scheduler, a simpler read-ahead mechanism, the lguest 'Linux-on-Linux' paravirtualization hypervisor, XEN guest support, KVM smp guest support, variable process argument length, SLUB is now the default slab allocator, SELinux protection for exploiting null dereferences using mmap, XFS and ext4 improvements, PPP over L2TP support, the 'lumpy' reclaim algorithm, a userspace driver framework, the O_CLOEXEC file descriptor flag, splice improvements, a new fallocate() syscall, lock statistics, support for multiqueue network devices, various new drivers and many other minor features and fixes.

domingo, octubre 07, 2007

PyMagazine!!!

Python Magazine es una revista orientada totalmente al lenguaje Python.
Acaba de comenzar a publicarse este mes y su primer ejemlar se puede descargar en PDF.
La revista está en inglés, algo que no creo que cambie ya que en estas pampas todo parece estar copado por .Net, Java y PHP.
La suscripción cuesta 60 dólares canadienses, casi $200 pesos argentinos. Creo que voy a necesitar hacerme de una tarjeta de crédito :-(
He leído un solo artículo, el de Steve Holden sobre las PyCONs, pero tiene artículos muy interesantes, uno de ellos trata sobre crear extensiones en C para Python :)

Fuente VivaLinux

martes, septiembre 11, 2007

Adiviná que OS estoy Usando, con VBox 1.5

La última actualización de Virtual Box (1.5), me ha sorprendido, integración seamless con el de las ventanas del huésped escritorio anfitrión! Todo a un apt-get de distanacia.

viernes, agosto 24, 2007

Recuperar Ubuntu/Debian

Esto es común cuando se instala Windows en un disco donde se tenía Linux instalado. El MBR es reescrito por el sistema de arranque de Microsoft.
Existen varias alternativas, una de estas, es descargar Smart Boot Manager e instalarlo en el disco en cuestión, nos mostrará un menú de arranque con todas las particiones.
La otra opción es reinstalar Grub (el programa que levanta Linux, el "menucito" ese que aparecía antes mostrándome los sistemas operativos disponibles para arrancar).
Para esto necesitamos arrancar con un CD o DVD de alguna distribución, y llegar a una consola de root.
Una vez en la consola debemos averiguar cual era la paritción que tenía instalado nuestro linux, para esto podemos usar diskdruid, cfdisk o fdisk -l. Paso siguiente es crear un punto de montaje para esta partición:
mkdir /mnt/linux
Tras crear el directorio debemos montar la partición
mount NOMBRE_PATICION /mnt/linux
Luego debemos montar dos pseudo-filesystems, a saber /proc y /dev
mount -o bind /proc /mnt/linux/proc
mount -o bind /dev /mnt/linux/dev
Ahora ya podemos hacer el cambio de raíz, que sería como volver a nuestro desaparecido linux.
chroot /mnt/linux
Nos queda instalar grub, mediante la utilidad grub-install
grub-install NOMBRE_PATICION

Espero que les halla sido útil!

sábado, agosto 04, 2007

SQLObject: Guardando Objetos en Una Base de Datos fácilmente.

SQLObject es un Mapeador de Objetos en Tablas de Bases de Datos, Object Relational Mapper o Object Relational Manager(o simplement ORMs). Si bien existen otros ORMs, como SQLAlchemy o el propio ORM de Django, SQLObject se caracteriza por su curva de aprendizaje de escasa pendiente.
Las bases de datos
Las Bases de Datos actuales se basan en el concepto de entidades (persona, auto, ejemplar) y relaciones (tiene, maneja, pertenece -Generalmente estos nombres se suelen usar en las etapas más primigenias de los modelos-).
Inicialmente se crea un modelo llamado conceptual, donde se utilizan 3 primitivas: especificación, generalización y agregación. Como las bases de datos no soportan el concepto de herencia (generalización), entre otras cosas, se va "bajando" el modelo, hacia un modelo lógico, que si es posible utilizar en una base de datos.
Para interactuar con estas bases de datos relacionales, se utiliza un lenguaje llamado SQL (Structured Query Language), que tiene su estandar y todo, pero como siempre, hay varios sabores.
Los comandos SQL se dividen en DDL y DML. DDL (Data Definition Language) es el lenguaje que nos permite generar y alterar la estructura de la base de datos. DML es el lenguaje de manipulación de datos, con el que podemos ingresar datos (INSERT), recuperar (SELECT), borrar (DELETE) y actualizar (UPDATE).
Dentro del software que usamos para las bases de datos tenemos: DBDesigner, Open System Architect (version Open Source de Data Architect), PGAdmin 3, MySQL Administrator, MySQL Query Browser, SQLiteman y SQLite Browser.
Los objetos
Los objetos se basan en diferentes principios de los que rigen las bases de datos (herencia, polimorfismo, encapsulamiento, persistencia, etc.). En un mundo ideal, con infinita memoria persistente, no necesitaríamos guardar objetos en una base de datos, pero, en el mundo real, debemos hacerlo.
Si pensamos en que es un objeto, en Python, vendrá a nuestras cabezas la idea del diccionario, de métodos(funciones) y atributos(variables).
En python, los atributos de instancia, son inicializados en el inicializador (o método __init__), de manera que de antemano, no podemos "ver" los atributos de la clase, así que de alguna manera tendremos que especificarle al ORM, que datos queremos guardar de nuestra clase.
También será necesario saber que tipo de datos queremos guardar de cada objeto. Un nombre será de tipo cadena, una fecha de tipo fecha, un precio de tipo flotante, y así con cada elemento de nuestro modelo de clases.
Acción
Bien, vamos que como se plasma toda esta cachara en código Python. Para esto voy a suponer que tienen SQLite instalado y SQLObject (con easy_install de las python-setuptool se instala perfectametne)
from sqlobject import *
# Esta es una base de datos en memoria
__connection__ = "sqlite:/:memory:"
class Persona(SQLObject):
nombre = StringCol(length=30)
apellido = StringCol(length=30)
altura = FloatCol()
Persona.createTable()
# Creamos tres personas, no hace falta que guardemos las instancias en p
# ya que no se las lleva el GC, están en la DB!!!
p = Persona(nombre = "Eduardeo", apellido = "Perez", altura = 1.96)
p = Persona(nombre = "Maria Laura", apellido = "Garatti", altura = 1.73)
p = Persona(nombre = "Pablo", apellido = "Martinez", altura = 1.68)

# Ahora recorremos las persona que generamos
for i in Persona.select():
print i
# Y ahora una connsulta con altura, pasando a condición SQL
for i in Persona.select("""altura > 1.70 """):
print i
Relaciones
Las relaciones entre objetos, pueden ser uno a uno, uno a muchos o muchos a muchos. En este aso el ejemplo es sencillo. Es una relación uno a muchos.
El ejemplo se trata de un modelo donde tenemos proveedores y productos.

#! /usr/bin/python

from sqlobject import *

# Para usar MySQL
# mysql:/usuario:pass@host/base

__connection__ = "sqlite:/:memory:"

class Proveedor(SQLObject):
nombre = StringCol(length=20)
direccion = StringCol(length=60)
def __str__(self):
return self.nombre

class Producto(SQLObject):
nombre = StringCol(length=20)
precio = FloatCol()
proveedor = ForeignKey('Proveedor')

def __str__(self):
return "Prod: %s $ %.2f" % (self.nombre, self.precio)

# El programa principal
if __name__ == "__main__":
for tabla in [ Proveedor, Producto]:
tabla.createTable()

p1 = Proveedor(nombre = "Muebles del Sur", direccion="Av. Alcorta Cicatriz")
p2 = Proveedor(nombre = "Muebles del Este", direccion="Zapiola 340")
p3 = Proveedor(nombre = "Equipamientos Fontana", direccion="Fontana 223")
# Para achicar un poco el codigo y usar algo de los hermosos tipo
# que python nos provee, armamos un diccionario con el proveedor
# como clave y una lista de tuplas (producto, precio)
datos_pro = { p1 : [('Silla', 120), ('Mesa', 150), ('alacena',200)],
p2 : [('Armario', 300), ('Frazada', 70),
('Pytho For Dummies', 9.99) ],
p3 : [('Martillo',25), ('Neumatico',200), ('Banco', 70)]

}
for prov, productos in datos_pro.iteritems():
for nombre, precio in productos:
Producto( nombre = nombre, precio = precio, proveedor = prov)
print "-"*40
print "Mostrando todos los productos:"
print "-"*40
for prod in Producto.select():
print prod
print "-"*40
# Un conjunto (set) tiene la propiedad de que sus elementos no se repiten
# a diferencia de una lista o un diccionario.
provs = set()

for p in Producto.select("""precio < 100"""):
provs.add(p.proveedor)
print "-"*40
print "Proveedores con productos de menos de $100:"
print "-"*40
for p in provs:
print "*", p
A diferencia de PyQt, donde es necesario mantener la referencia al objeto una vez instanciado para que el Garbage Collector no nos lo borre, en este caso, con cada instancia que generamos se genera una tupla en la base de datos. De manera que no es necesario guardar estas referencias. El método select(), que heredamos de las clase SQLObject, nos permite hacer consultas. Le pasamos como argumento, lo que podríamos en el WHERE de nuestro SQL.

Si bien es necesario saber algo de SQL para sacarle el jugo, es evidente las facilidad con la que persistimos objetos.
SQLObject tiene muchas cosas interesantes, de hecho, es el ORM de TurboGears, un framework web ala Rails.

miércoles, julio 11, 2007

Hacia Kubuntu.... y una noticia triste: Despedida a Con Kolivas

Ya hace una semana y un día que estoy utilizando Kubuntu, luego de haber terminado de destruir un Debian que había sufrido casi todos mis caprichos.
Tengo ciertos puntos a favor de Kubuntu en el corto tiempo que lo estoy usando:
  • Software más actualizado para Desktop/Desarrollo.
    En particular, Python, OpenOffice, Amarok.
  • Mucha documentación muy fácil y redundante.
  • Muchos repositorios bastante serios para nutrir a la distro con software adicional.
    Con serios me refiero a que no rompen dependencias con otros paquetes del mainstream y cosas por el estilo.
  • Cosas de moda, a pocos apt-get... como compiz-fussion. Al ser una ditro popular, siempre hay alguien compilando lo que queremos :)
Sin embargo encontré varios detalles molestos. Pocas imágenes de núcleo por defecto y performance bastante mala en comparación a Debian. Mucho menos software en los repositorios. Tiempos de arranque más prolongados.

Finalmente, respeta perfectamente muchos de los mecanismos de debianero, por ejemplo, el make-kpkg, para crear una imagen del kernel y unos headers (para nvidia, vmware, etc.). Así que solucionar el tema del kernel por defecto no tuvo mayores complicaciones. Creo que voy a quedarme con Kubuntu por algún tiempo.
Por último una pálida: Al bajar los parches de Con Kolivas para el kernel 2.6.22, me enteré que la versión 2.6.22-ck1 será la última.
Veremos que nos depara el planificador totalmente justo de Ingo Molnar en el release 2.6.23.

martes, julio 10, 2007

Mejorando compatibilidad de Wine


Vía Vivalinux me enteré que se liberó Wine-Doors, una aplicación escrita en PyGTK, que nos permite instalar varios programas de winblows en nuestro wine, como por ejemplo, QuickTime, DVD Decrypter, varias fuentes, runtimes de Micro$oft, y algunos juegos, como Half Life o WoW 2.

miércoles, junio 27, 2007

Creación de una calculadora con Python y PyQt4

Introducción:
Vamos a emprender la "aventura" de crear una calculadora. Python nos va a ayudar con su introspección y sus tipos de datos diccionario, lista y tupla; Qt nos va a dar una mano con sus mecanismos de conexión y algunas propiedades útiles que define en su clase base principal, QObject.
Por último, y para hacer menos aburrido el tema, usaremos un autómata finito (aka. maquina de estados) para emular el comportamiento de esas calculadoras económicas de bolsillo, desarrolladas en algún país del este...
Diseño de la interfase:Para esto, utilizaremos el diseñador de Qt, en Debian el binario se llama designer (o designer-qt4 si se tiene Qt3 y Qt4 instalados).
Es una buena oportunidad de usar los layouts, en especial, uno que no usamos a menudo, el layout matricial, o de celdas (QGridLayout).
Luego de jugar un rato, podremos hacer algo como lo siguiente:

Donde hemos definido los nombres de los objetos, respetando un patrón, en este caso, los digitos, se llaman btn_digit_, ej: btn_digit_1, btn_digit_2, btn_digit_3, etc.

Desde tenemos algunos atajos muy útiles, CTRT+R para probar la interfase, F1 para obtener la información del Widget que tenemos seleccionado y CTRL+I, para acceder al diálogo de propiedades del Widget, donde editamos la paleta, las fuentes, dimensiones y demás propiedades netamente visuales.
El .ui de la interfase se puede descargar aquí: interfase.ui
En este ejemplo, he usado el mecanismo de herencia múltiple, no el de carga dinámica.
Para esto tenemos que compilar el .ui en un .py, para automatizar la tarea, suelo usar un Makefile, como este.
Lógica de la calculadora:
Si estuviésemos programando en Visual Basic, Delphi o cualquier otro entorno orientado a eventos, seguramente pondríamos el código de la aplicación en cada pulsación de cada botón, pero en este caso, utilizaremos un autómata.
Un automata finito se define como un alfabeto de entrada (en este caso, los botones de la calculadora), un conjunto de estados, un cojunto de transiciones y un conjunto de acciones asociadas a cada transición.
La maquina de estados se inicializa en algún estado inicial, y a medida que va recibiendo entrada, irá saltando de estado en estado, y realizando las funciones asociadas.
En este caso, la calculadora cuenta con un solo lugar de almacenamiento (o acumulador), además usa la pantalla como buffer temporal de los datos. Tendrá la capacidad de recordar una operación.
El automata consiste en un módulo a parte, llamado automata.py, que posee la tabla de transiciones, y la función que ejecuta las transiciones de acuerdo a la entrada.

automata = {
    'en_cero'   : {
        'cero':      ('cero', [] ),
        'digito':    ('primer_dig', ['establecer']),
        'operacion': ('operando', ['almacenar']),
        'igual':     ('cero',[]),
        'clear':     ('en_cero',['limpiar']),
    },
    'primer_dig': {
        'cero':      ('primer_dig',['actualizar']),
        'digito':    ('primer_dig',['actualizar']),
        'operacion': ('operando',  ['guardar_op', 'almacenar']),
        'igual':     ('resultado', ['almacenar']),
        'clear':     ('en_cero',['limpiar']),
    },
    'operando': {
        'cero':      ('cero_dos', ['establecer']),
        'digito':    ('segundo_dig', ['establecer']),
        'operacion': ('resultado', ['operar']),
        'igual':     ('resultado',['operar']),
        'clear':     ('en_cero',['limpiar']),
    },
    'cero_dos': {
        'cero':      ('cero_dos', []),
        'digito':    ('segundo_dig',['establecer']),
        'operacion': ('cero_dos', []),
        'iugal':     ('cero_dos', []),
        'clear':     ('en_cero',['limpiar']),
    },
    'segundo_dig' : {
        'cero':      ('segundo_dig', ['actualizar']),
        'digito':    ('segundo_dig', ['actualizar']),
        'operacion': ('resultado', ['guardar_op','operar']),
        'igual':     ('resultado', ['operar']),
        'clear':     ('en_cero',['limpiar']),
    },
    'resultado': {
        'cero':      ('en_cero', ['establecer']),
        'digito':    ('primer_dig', ['establecer']),
        'operacion': ('operando',['almacenar', 'guardar_op']),
        'igual':     ('resultado',[]),
        'clear':     ('en_cero',['limpiar']),
    },
}

Para generalizar esta lógica, utilizaremos las capacidades de introspección de Python.
¿Que es esto?
Bueno, es implemente dada una instanacia, obtener una función (que es un objeto después de todo, no?)
funcion = getattr(instancia, "nombre")
funcion(arg1, arg2)
Jejeje, muy fácil. De esta manera, para ejecutar el autómata tenemos una función muy simple:

def ejecutar_automata( caracter, vista ):
    '''Ejecuta la logia de la caluladora.'''
    entrada = tipo_entrada[str(caracter)]
    transicion = automata[ getattr(vista, "estado") ][entrada]
    # Realizar la lista de acciones relacionadas con el cambio de estado
    # si es que existen...
    if transicion[FUNCIONES]:
        for i in transicion[FUNCIONES]:
            if DEBUG:
                print "estado %s > %s(%s)" % (getattr(vista, "estado") ,i, caracter)
            accion = getattr(vista, i)
            accion(caracter)

    if DEBUG:
        print "Cambiando a %s" % (transicion[PROXIMO_ESTADO])
    setattr(vista, "estado", transicion[PROXIMO_ESTADO])
El código del autómata se puede ver completo en: automata.py
Vemos que la función recibe una vista como parámetro. Viene a ser algo así como un patrón visitante venido a menos.
Por último, tenemos que generar la aplicación y hereder de QMainWindow, relaizar los connects y ponerle un splash...

#! /usr/bin/python
# *-* encoding: utf-8 *-*

#
# Autor: Nahuel Deofossé (c) 2007
# Licencia: GPL
#

# Todo PyQt4 :)
from PyQt4.Qt import *

# Generado a través del editor de designar
# cuando se actualiza el GUI, se debe correr Make para que
# se transformen en código
from interfase import Ui_MainWindow
# Para los argumentos de linea de entrada
import sys
# Todas las definiciones del automata que hemos separado en otro modulo (py)
from automata import ejecutar_automata

# Algunas funciones utiles


class Calculadora(QApplication):
    '''Aplicacion calculadora simple'''
    def __init__(self, *argumentos):
        QApplication.__init__(self, *argumentos)
        splash_pxmap = QPixmap("./resources/splash.png")
        splash = QSplashScreen(splash_pxmap)
        splash.show()
        ventana = VentanaCalculadora()
        ventana.show()
        splash.finish(ventana)
        self.exec_()

class VentanaCalculadora(QMainWindow, Ui_MainWindow):
    '''GUI de la calculadora.'''
    estado = "en_cero"  # De acuerdo a los estados del automata
    valor = 0
    operacion = ""
    def __init__(self, padre = None):
        '''Constructor de la ventana'''
        QMainWindow.__init__(self, padre)
        self.setupUi(self)
        self.connect(self.actionSalir, SIGNAL("triggered()"), qApp.exit )
        # Conectamos los digitos
        for i in [  self.btn_digit_1, self.btn_digit_2,
                    self.btn_digit_3, self.btn_digit_4,
                    self.btn_digit_5, self.btn_digit_6,
                    self.btn_digit_7, self.btn_digit_8,
                    self.btn_digit_9, self.btn_digit_0,
                    ]:
            self.connect(i, SIGNAL("clicked()"), self.in_digito)
    # Ahora conectamos las operaciones

    def in_digito(self):
        '''Pulsado de un digito'''
        num = self.sender().objectName()[-1:]
        ejecutar_automata(num, self)

    def on_btn_op_add_pressed(self):
        ejecutar_automata("+", self)

    def on_btn_op_sub_pressed(self):
        ejecutar_automata("-", self)

    def on_btn_op_mul_pressed(self):
        ejecutar_automata("*", self)

    def on_btn_op_div_pressed(self):
        ejecutar_automata("/", self)

    def on_btn_op_res_pressed(self):
        ejecutar_automata("=", self)

    def on_btn_clear_pressed(self):
        ejecutar_automata("c", self)



    # Funciones que llama el automata
    def actualizar(self, c):
        '''Agrega un caracter al display '''
        self.lineResultado.setText( self.lineResultado.text() + c )

    def establecer(self, c):
        '''Establece el valor del display'''
        self.lineResultado.setText(c)
    def operar(self, c):
        pass

    def almacenar(self, c):
        self.valor = float(self.lineResultado.text())

    def guardar_op(self,c):
        self.operacion = c

    def operar(self, c):
        result = 0
        self.valor2 = float(self.lineResultado.text())
        if self.operacion == "+":
            result = self.valor + self.valor2
        elif self.operacion == "-":
            result = self.valor - self.valor2
        elif self.operacion == "/":
            result = self.valor / self.valor2
        elif self.operacion == "*":
            result = self.valor * self.valor2
        else:
            print "Nada"
        self.lineResultado.setText(str(result))

    def limpiar(self, c):
        self.lineResultado.setText("0")
        self.valor = 0


if __name__ == "__main__":
    app = Calculadora(sys.argv)
Como verán, el código es muy simple y corto. Se puede extender con facilidad.
Hemos visto varias cosas interesantes de Python y de PyQt.
Un diagrama, de lo que sucede sería como el siguietnte:

En el rectángulo verde vemos el conjunto de los eventos, el rectángulo rojo es el autómta y sobre la esquina superior derecha, el rectángulo naranja es el estado que se mantiene en la vista... y las funciones que cuelgan, son las que el autómata utiliza como interface para modificar el estado de la vista...
Finalmente, habrán notado que he mezclado el estado (modelo) con la vista, en este caso, generar una separación complicaba las cosas -llevando las cosas fuera del scope de lo que quería mostrar-.

El código completo se encuentra en:
https://github.com/D3f0/calculadora/edit/master/README