Error importando OAuthSignatureMethod_HMAC_SHA1 en python-oauth

jueves, octubre 25, 2012

Si estás utilizando la librería python-oauth para autenticarte contra un servicio por medio de OAuth y te consigues con el error:
AttributeError: 'module' object has no attribute 'OAuthSignatureMethod_HMAC_SHA1'

Entonces tengo la solución para ti.

El problema es que la clase no está en el módulo oauth, sino en oauth.oauth. Entonces, en lugar de hacer:
import oauth

Prueba con:
try:
    import oauth.oauth
except:
    import oauth

De nada ;)

Referencias:

Personalizar el unity-greeter de LightDM en ArchLinux

martes, octubre 09, 2012

Buscando opciones para un gestor de inicio de sesión bonito y ligero recordé a LightDM. Sé que seguramente me van a hablar de SLiM, pero ha estado abandonado mucho tiempo y no es tan lindo y funcional como LightDM, así que decidí no utilizarlo.

Instalación

LightDM se encuentra disponible en AUR, así que una buena forma de instalarlo es con yaourt: $ yaourt -S lightdm lightdm-unity-greeter
Para más información de cómo instalar LigthDM visita la wiki de ArchLinux.

Configuración

Esta es la parte divertida. Muchas recetas en internet te hablan de editar el infame /etc/lightdm/lightdm-unity-greeter.conf, pero la verdad es que la versión más nueva no utiliza ese archivo sino que, "en teoría", utiliza dinámicamente la imagen establecida como fondo de pantalla para el fondo del greeter. En mi caso siempre usaba la misma imagen, la que trae Ubuntu por defecto. Incluso agregué mi imagen a la ruta /usr/share/backgrounds/ y tampoco funcionaba.

¿Qué hacemos? Pues editemos el schema del dconf a mano. Abrimos con nuestro editor favorito el archivo usr/share/glib-2.0/schemas/com.canonical.unity-greeter.gschema.xml y ajustamos los valores correspondientes.

Yo edité solamente la línea del background y del color de fondo:
<key name="background" type="s">
  <default>'/usr/share/backgrounds/poweroff.jpg'</default>
  <summary>Background file to use, either an image path or a color</summary>
</key>
...
<key name="background-color" type="s">
  <default>'#444444'</default>
  <summary>Background color (e.g. #772953), set before wallpaper is seen</summary>
</key>

En el key con nombre "background" cambié la ruta al archivo de fondo, apuntando a /usr/share/backgrounds/poweroff.jpg y en el key con nombre "background-color" cambié el color a #444444. Ustedes editen los campos como mejor les parezca.

Para que estos cambios tengan efecto debemos recompilar los esquemas del dconf, así que ejecutamos: # glib-compile-schemas /usr/share/glib-2.0/schemas/
Reiniciamos el servicio y ya estaremos disfrutando de nuestros cambios en el gestor.

Espero que les haya servido esta receta.

Referencias

Respaldar archivos usando Rsync

martes, septiembre 18, 2012

En ocasiones nos toca respaldar gran cantidad de información de un equipo a otro y una de las maneras más cómodas de hacerlo es a través de la red. Para esta tarea usaremos Rsync que, al igual que netcat, son unas navajas suizas en lo que a red se refiere. Rsync, entre otras cosas, nos permite sincronizar directorios a través de la red y de esa forma lo usaremos para enviar nuestros archivos de un equipo a otro.

Comando y parámetros

Lo primero que necesitamos es acceso vía SSH al equipo remoto. Puede ser por clave pública o con usuario y contraseña. Luego nos ubicamos en la carpeta que queremos respaldar y ejecutamos el comando: $ rsync -ravz archivo_a_respaldar usuario@IP:directorio_destino Donde:
  • r: recorre los directorios de manera recursiva
  • a: conserva los atributos de los archivos (usuario, permisos, etc)
  • v: imprime información en pantalla
  • z: comprime los datos antes de enviar
Luego de la autenticación comenzará la copia de los archivos. Es importante resaltar que en el directorio_destino debemos colocar la ruta absoluta a la carpeta.

Copiar un archivo

Supongamos que queremos respaldar el archivo backup.tar.gz en un equipo remoto con IP 192.168.0.3, el usuario es satanas y el directorio destino es el home del usuario, el comando nos quedaría así:
$ rsync -avz backup.tar.gz satanas@192.168.0.3:~
El símbolo ~ puede sustituirse por la ruta absoluta /home/satanas.

Copiar un directorio y todos sus subdirectorios

Ahora supongamos que queremos respaldar el directorio /tmp/music en el mismo equipo anterior pero ahora el destino es la carpeta /home/satanas/musica, el comando nos quedaría así: $ rsync -ravz /tmp/music satanas@192.168.0.3:/home/satanas/musica

Con esta receta podremos pasar nuestro respaldo de archivos de un equipo a otro sin mucho inconveniente. Espero que les sirva

Tip: Obtener el espacio usado de un directorio

jueves, marzo 22, 2012

Situación

Queremos conocer el espacio en disco usado por un directorio (y sus subdirectorios inmediatos) con un comando de consola.

Comando

$ du -h -s /tu/directorio/*

Resultado

El comando te imprimirá algo como:
$ du -h --summarize /tu/directorio/*
2.5M /var/backups
286M /var/cache
139M /var/lib
4.1k /var/local
4.1k /var/lock
98M /var/log
4.4M /var/mail
4.1k /var/opt
103k /var/run
66k /var/spool
4.1k /var/tmp

Explicación

El comando du te da un estimado del espacio utilizado por un directorio, la opción -h te imprime los números en potencias de 1024, --sumarize muestra solo el total para cada elemento y /tu/directorio/* corresponde al directorio que deseas analizar. El * al final es la clave para indicarle al comando que queremos ver los subdirectorios.

Configurar opciones por defecto para el comando gem

sábado, marzo 10, 2012

Cada vez que voy a instalar una gema con el comando gem uso los parámetros --no-rdoc y --no-ri para que no me genere la documentación, principalmente porque nunca la uso y además demora demasiado el tiempo de instalación de las gemas. Pero escribir esos parámetros cada vez que ejecuto el comando es fastidioso.

Afortunadamente gem busca el archivo de configuración ~/.gemrc en el directorio personal del usuario y aplica las opciones que estén definidas, así que creando ese archivo en nuestro home con la siguiente línea no tendremos que tipear las opciones nunca más:

gem: --no-rdoc --no-ri

Enviar mensajes a través de D-Bus usando Python

martes, febrero 14, 2012

D-Bus es un sistema que permite la comunicación entre diferentes procesos. Es desarrollado como parte del proyecto freedesktop.org buscando ofrecer una solución simple y común para los distintos entornos de escritorio.

Conceptos básicos


Tipos de Bus

Hay dos tipos de buses que se pueden usar con D-Bus. El bus de sesión, que se crea con cada sesión de usuario y es local a esa sesión, y el bus de sistema. Este último es global, se inicia cuando arranca el equipo y generalmente se utiliza para comunicarse con procesos como udev, NetworkManager o HAL.

Rutas a Objetos

Cada lenguaje de programación tiene sus objetos nativos (usualmente representados por clases). La ruta a un objeto es la forma en que D-Bus permite hacer referencia a un objeto nativo y que las aplicaciones remotas puedan usarlo. Un ruta a un objeto luce como la ruta de un archivo (Unix-like) y es común generarlas como un nombre de dominio en reversa, por ejemplo: /org/gnome/myapp/MyObject. Sin embargo, cada desarrollador puede usar la ruta que mejor le parezca, siempre y cuando sea única.

Métodos y Señales

Los métodos son operaciones (con o sin parámetros) que pueden invocarse en un objeto y que eventualmente pueden devolver un resultado. Las señales son notificaciones que se envían al bus y son recibidas por los observadores (objetos que escuchan o se conectan a esas señales). Estas señales también pueden enviar datos de interés para el receptor.

Objetos Proxy

Un objeto proxy no es más que un objeto Python que viene a representar a un objeto remoto en otro proceso. Esto nos permite emplear los métodos del objeto remoto como si fueran métodos nativos. Para instanciar un objeto proxy necesitamos la "ruta del objeto".

Estructura Básica

Para usar D-Bus es importante entender la estructura e interacciones básicas. En palabras simples, lo que tenemos son dos aplicaciones que se "hablan" entre sí a través de un canal común. Generalmente una de ellas actúa como "servidor", ofreciendo métodos y señales que podrán ser usados por una aplicación "cliente". En la imagen a continuación se ilustra claramente el concepto.



Un ejemplo bastante común es el funcionamiento de un reproductor de música (como el servidor) que ofrece métodos para informar sobre su estado actual y una aplicación de notificaciones (como cliente) que usa estos métodos para mostrar diálogos en el escritorio cada vez que cambia una canción.

Aplicación "servidor"


Lo primero que debemos hacer para empezar a trabajar con D-Bus es conectarnos a un bus. En nuestro caso será al bus de sesión porque no nos interesa interactuar con procesos del sistema operativo.

Adicionalmente, para ejecutar llamadas asíncronas a los métodos (y que la aplicación no se bloquee mientras espera) debemos configurar un bucle principal. Para el momento de escribir este post, python-dbus solo soporta el bucle principal de GLib, así que usaremos esas librerías para crear nuestro loop.

Los import que necesitamos para esto serían:
import dbus
import dbus.service
import gobject

from dbus.mainloop.glib import DBusGMainLoop

Luego, definimos (en variable globales) el nombre del bus y la ruta de nuestro objeto:
DBUS_BUSNAME = 'org.example.ExampleDBus'
DBUS_MYOBJECT_PATH = '/org/example/ExampleDBus/MyObject'

Ahora definimos la clase de nuestro server, con la inicialización mínima para que funcione D-Bus:
class DBusService(dbus.service.Object):
    
    def __init__(self):
        # Le indicamos a D-Bus que usaremos el loop de GLib como bucle
        # predeterminado
        DBusGMainLoop(set_as_default=True)
        
        # Establecemos la conexión al bus de sesión
        self.session_bus = dbus.SessionBus()
        name = dbus.service.BusName(DBUS_BUSNAME, self.session_bus)
        
        # Inicializamos el objeto D-Bus
        dbus.service.Object.__init__(self, self.session_bus, DBUS_MYOBJECT_PATH)
        
        # Arrancamos el bucle principal
        loop = gobject.MainLoop()
        
        # Colocamos el loop dentro de un try/except para detectar cuando el 
        # usuario presione Ctrl + C y finalizar la aplicación limpiamente
        try:
            print "Servicio DBus iniciado"
            loop.run()
        except KeyboardInterrupt:
            loop.quit()
            print "Servicio DBus finalizado"

Si se fijan en el código anterior, nuestra clase hereda de dbus.service.Object (porque estamos construyendo un objeto D-Bus que será instanciado por una aplicación remota). En la inicialización le indicamos a D-Bus que usaremos el loop de GLib, establecemos la conexión al bus de sesión y arrancamos el loop.

He decidido colocar la ejecución del loop principal dentro de un try/except para que el usuario pueda usar Ctrl + C para salir elegantemente de la aplicación.

Hecho esto podemos proceder a definir un par de métodos. Hagamos un método que imprima un saludo y otro que nos devuelva un valor, en este caso la hora.
    @dbus.service.method(DBUS_BUSNAME)
    def say_hello(self, name):
        print "Hola, %s" % name
    
    @dbus.service.method(DBUS_BUSNAME)
    def get_time(self):
        return time.strftime("%H:%M")

En los párrafos previos comenté que un objeto proxy no es más que una representación de un objeto D-Bus en un objeto Python, así que para exportar un método nativo como método D-Bus usamos el decorador @dbus.service.method y le pasamos como parámetro el nombre del bus. Luego definimos nuestras funciones como lo haríamos normalmente en cualquier clase de Python y ya con esto tendríamos un servidor muy básico listo para funcionar.

El código completo debería quedar así:
#!/usr/bin/python
# -*- coding: utf-8 -*-

import time
import dbus
import gobject
import dbus.service

from dbus.mainloop.glib import DBusGMainLoop

DBUS_BUSNAME = 'org.example.ExampleDBus'
DBUS_MYOBJECT_PATH = '/org/example/ExampleDBus/MyObject'

class DBusService(dbus.service.Object):
    
    def __init__(self):
        # Le indicamos a D-Bus que usaremos el loop de GLib como bucle
        # predeterminado
        DBusGMainLoop(set_as_default=True)
        
        # Establecemos la conexión al bus de sesión
        self.session_bus = dbus.SessionBus()
        name = dbus.service.BusName(DBUS_BUSNAME, self.session_bus)
        
        # Inicializamos el objeto D-Bus
        dbus.service.Object.__init__(self, self.session_bus, DBUS_MYOBJECT_PATH)
        
        # Arrancamos el bucle principal
        loop = gobject.MainLoop()
        
        # Colocamos el loop dentro de un try/except para detectar cuando el 
        # usuario presione Ctrl + C y finalizar la aplicación limpiamente
        try:
            print "Servicio DBus iniciado"
            loop.run()
        except KeyboardInterrupt:
            loop.quit()
            print "Servicio DBus finalizado"
        
    @dbus.service.method(DBUS_BUSNAME)
    def say_hello(self, name):
        print "Hola, %s" % name
    
    @dbus.service.method(DBUS_BUSNAME)
    def get_time(self):
        return time.strftime("%H:%M")
    
    @dbus.service.signal(DBUS_BUSNAME)
    def kill(self):
        return 'killed'

if __name__ == '__main__':
    service = DBusService()

Aplicación "cliente"

La aplicación cliente es mucho más simple. La única librería que necesitamos es la de D-Bus, el nombre del bus y la ruta del objeto.
import dbus

DBUS_BUSNAME = 'org.example.ExampleDBus'
DBUS_MYOBJECT_PATH = '/org/example/ExampleDBus/MyObject'

Ahora pasemos a crear la clase. Al igual que en el servidor, necesitamos establecer la conexión con el bus y "mapear" el objeto D-Bus en un objeto Python. En este caso la variable self.my_object es la que contiene la representación de dicho objeto.
class DBusClient:
    
    def __init__(self):
        self.session_bus = dbus.SessionBus()
        self.my_object = self.session_bus.get_object(DBUS_BUSNAME, 
            DBUS_MYOBJECT_PATH)

Para llamar a un método del objeto remoto debemos importar el método correspondiente, y como estaremos usando varios métodos vamos a crear una función interna que nos ayude con esta tarea.
    def __get_dbus_method(self, name):
        return self.my_object.get_dbus_method(name)

Procedemos a crear nuestros métodos nativos que obtendrán el método remoto del objeto D-Bus y lo llamarán con los parámetros correspondientes según sea el caso.
    def say_hello(self, name):
        # Almacenamos el método en una variable y luego lo llamamos con los
        # parámetros correspondientes
        method = self.__get_dbus_method('say_hello')
        method(name)
    
    def print_time(self):
        method = self.__get_dbus_method('get_time')
        # Obtenemos el valor de retorno del método y la imprimimos en pantalla
        current_time = method()
        print "Son las %s" % current_time

Con eso ya deberíamos tener un cliente funcional. El código completo del cliente debería quedar algo como:
#!/usr/bin/python
# -*- coding: utf-8 -*-

import dbus

DBUS_BUSNAME = 'org.example.ExampleDBus'
DBUS_MYOBJECT_PATH = '/org/example/ExampleDBus/MyObject'
        
class DBusClient:
    
    def __init__(self):
        self.session_bus = dbus.SessionBus()
        self.my_object = self.session_bus.get_object(DBUS_BUSNAME, 
            DBUS_MYOBJECT_PATH)
    
    def __get_dbus_method(self, name):
        return self.my_object.get_dbus_method(name)
        
    def say_hello(self, name):
        # Almacenamos el método en una variable y luego lo llamamos con los
        # parámetros correspondientes
        method = self.__get_dbus_method('say_hello')
        method(name)
    
    def print_time(self):
        method = self.__get_dbus_method('get_time')
        # Obtenemos el valor de retorno del método y la imprimimos en pantalla
        current_time = method()
        print "Son las %s" % current_time

if __name__ == '__main__':
    client = DBusClient()
    client.say_hello('Pedro')
    client.say_hello('Maria')
    client.print_time()
Es importante que observe que al ejecutar el script del cliente se llamará al método say_hello dos veces (con los parámetros 'Pedro' y 'Maria' respectivamente) y luego al método print_time.

Pruebas

Para probar abrimos dos terminales. En la primera ejecutamos el script del servidor (yo lo llamé dbus_service.py) y veremos algo como:
$ python dbus_service.py 
Servicio DBus iniciado
Con un mensaje indicándonos que el servicio está corriendo y esperando ser utilizado.

En la segunda terminal ejecutamos el script del cliente (lo llamé dbus_client.py) y veremos algo como:
$ python dbus_client.py 
Son las 12:55
Muy bien, imprimió la hora pero... ¿No se suponía que también habíamos llamado al método say_hello dos veces? ¿Qué pasó?

Bueno, volvamos a ver la terminal del servicio y veremos nuestro ansiado resultado:
$ python dbus_service.py 
Servicio DBus iniciado
Hola, Pedro
Hola, Maria

Tal como lo esperabamos, el método say_hello imprime en la instancia del servidor el nombre envíado desde el cliente y por otro lado, el cliente imprime la hora que le devuelve el método get_time desde el servidor. Hemos enviado mensajes en ambas direcciones usando D-Bus, ¡todo un éxito!

Espero que esta receta simple les haya ayudado a comprender como funciona D-Bus y como usarlo desde Python. Más adelante estaré escribiendo otros posts sobre cómo emitir/recibir señales y cómo enviar grandes cantidades de datos "al vuelo" a través de D-Bus.

Fuentes:

Mostrar el log de ActiveRecord en la consola de Rails

miércoles, febrero 01, 2012

Si usualmente utilizas la consola interactiva de Ruby On Rails para realizar pruebas, correr tareas de Rake, entre otras cosas y te resultaría sumamente útil ver el log de lo que esta haciendo el ActiveRecord, entonces este tip es para ti.

Simplemente ejecuta la consola desde la carpeta raíz de tu aplicación Rails:

Para rails 3.x:
$ rails c
Para rails 2.x:
$ script/console
Y luego indícale al logger que use la salida estándar:
ActiveRecord::Base.logger = Logger.new(STDOUT)
Con eso los mensajes de log del ActiveRecord se imprimirán en la consola.