Archive by Author

Alternativa al sistema de templates de Django, parte 1: Jinja2

Django es un gran framework web pero tiene un sistema de templates que a un programador puede resultarle un tanto limitado:

  • No es posible asignar variables ni cambiar sus valores.
  • No hay distinción entre métodos y propiedades.
  • No es posible pasar parámetros a los métodos.
  • No existe la sentencia elif ! :P

Hay varias alternativas entre las que elegir: Jinja2, Mako, Genshi, Cheetah. De todas, Jinja2 es el que tiene la sintáxis más compatible con Django, pero tiene otra filosofía y por lo tanto permite hacer más cosas. Empecemos entonces por la instalación.

Instalación de Jinja2

Jinja puede instalarse medianteeasy_install:

sudo easy_install jinja2

Y medianteapten debian y derivados:

sudo apt-get install python-jinja2

Integración con Django

El diseño de bajo acoplamiento de Django permite que usar otro sistema de templates sea sencillo. Para Jinja basta con definir una variable de ambiente y escribir los métodos alternativos pararender_to_stringyrender_to_response. A continuación muestro la forma más simple que encontré. Hay otras más sofisticadas por ahí (esta y esta) pero básicamente hacen lo mismo:

# jinja_helper.py
from django.conf import settings
from django.http import HttpResponse
from jinja2 import Environment, FileSystemLoader

jinja_env = Environment(
    loader=FileSystemLoader(getattr(settings, 'TEMPLATE_DIRS')))

def render_to_string(template_path, context=None, **kwargs):
    template = jinja_env.get_template(template_path)
    context = dict(context or {})
    return template.render(**context)

def render_to_response(template_path, context=None, **kwargs):
    return HttpResponse(render_to_string(template_path, context, **kwargs),
                        mimetype=None)

La vista entonces no difiere mucho de una vista tradicional:

# views.py
from jinja_helper import render_to_response

def index(request):
    title = "hello world."
    return render_to_response('index.html', locals())
<!-- index.html -->
<h1>{{ title }}</h1>


Read more »

Tags: , ,

Debian squeeze en Samsung N210

La semana pasada me compré una netbook Samsung N210 con la cual estoy muy contento. Le instalé Debian squeeze (testing) y logré configurarle todas las teclas especiales, incluyendo las usadas para regular el brillo de la pantalla. Me basé en varias guías como esta y esta otra, aunque no las seguí exactamente y es por eso el motivo del post.

Antes de comenzar la guía (y suponiendo que como yo, estás leyendo esto antes de comprar la máquina) te cuento mi experiencia con este aparatito. Algo que me hacía dudar en comprarme o no una netbook era el teclado que traían: demasiado chicos o sin espacio entre teclas. La N210 tiene casi la misma distancia entre la A y la Ñ que los teclados de escritorio y además tiene las teclas separadas como para que los dedos reconozcan mejor dónde están ubicados. Lo encuentro bastante cómodo y agradable de usar y salvo por un par de teclas que complican un poco (la < se encuentra sobre la derecha y el shift derecho es chico) me siento a gusto con él. Por otro lado la batería dura aprox. 7 hs (con el brillo casi a tope) contra las 11 que declara Samsung. Dudo que llegue a eso incluso desconectando la wifi, bluetooth y poniendo el brillo al mínimo, pero aun así destaca su autonomía. Otra característica que me gusta es que es silenciosa y calienta muy poco.

Una última cosa antes de comenzar: El microprocesador Atom N450 tiene tecnología Hyperthreading que paraleliza el procesador físico en dos procesadores virtuales. Es por eso que la salida de/proc/cpuinfomuestra dos cpus.

Ahora sí, vamos a la guía.


Read more »

Tags: , ,

Reemplazo de discos en RAID con mdadm

Hace unos días hice mi segundo reemplazo completo de discos de un array MD y quería compartir aquí los pasos que he utilizado (con éxito :D) en ambos casos.

Los dos escenarios fueron similares: dos discos iguales, con iguales particiones y RAID-1 que deben ser reemplazados por otros dos discos iguales pero de mayor tamaño, por lo que el procedimiento fue el mismo en ambos casos.

Para simplificar la guía decidí usar discos con sólo tres particiones: una para/, una para/vary otra paraswap(que no está en RAID). El esquema entonces queda definido de la siguiente manera:

sda (grub)               RAID's 1                sdb (grub)
+------------------+     +-----------------+     +------------------+
| /dev/sda1        |-----| /dev/md0 (/)    |-----| /dev/sdb1        |
+------------------+     +-----------------+     +------------------+
| /dev/sda2        |-----| /dev/md1 (/var) |-----| /dev/sdb2        |
+------------------+     +-----------------+     +------------------+
| /dev/sda3 (swap) |                             | /dev/sdb3 (swap) |
+------------------+                             +------------------+

Los discos que se usarán para reemplazo sonsdcysdd.

NOTA: En la guía sólo se muestra el reemplazo completo de sda por sdc ya que el procedimiento para reemplazar sdb por sdd es el mismo.

1. Particionado de disco

La manera sencilla de copiar la tabla de particiones de una unidad a otra es:

papua:~# sfdisk -d /dev/sda | sfdisk /dev/sdc

Esto copia completamente el esquema del disco origen (sda) al disco destino (sdc). Si el destino es mayor simplemente quedará espacio libre (sin asignar) al final del disco.

2. Reemplazo de particiones en arrays

TIP: Es útil tener visible, en otra terminal y durante todo el proceso, la salida de/proc/mdstatpara visualizar en todo momento el estado del array y poder ver el sincronizado de los discos:

papua:~# watch -t cat /proc/mdstat


Read more »

Tags:

Vim scripting con Python

Vim permite agregar funcionalidades mediante varios lenguajes externos, entre ellos Perl, Python, Ruby y Tcl. Para poder hacer uso de esta característica es necesario haber compilado Vim con el soporte para el lenguaje necesario (con el flag-python, para soporte python). En debian existe un paquete llamado vim-nox (no X) que contiene una versión compilada con soporte para los cuatro lenguajes mencionados:

sudo apt-get install vim-nox

Para comprobar que efectivamente se encuentre habilitado el soporte para Python ejecutar Vim y en modo comando escribir:

:echo has("python")

Un 1 indica que Vim interpreta Python ;)

Es muy recomendable leer la ayuda en línea:

:help python

También se puede acceder vía web desde http://vimdoc.sourceforge.net/htmldoc/if_pyth.html

Ejecución de código Python

La ejecución de una línea de código Python se realiza según la sintaxis:

:[range]py[thon] {stmt}

Ejemplo:

:python print "hello world"

Aquí el prompt mostrará el mensaje “hello world”.

En cambio para escribir código en varias líneas hay que usar la siguiente forma:

[range]:py[thon] < < {endmarker}
{script}
{endmarker}

Ejemplo:

:python < < EOF
def get_user():
  import os
  return os.getenv('USER')
EOF

De esta manera la función queda guardada en la memoria de la sesión actual. Luego su uso podría ser el siguiente:

:py user = get_user()

Tambien es posible cargar y/o ejecutar código desde un archivo externo. La sintaxis es:

:[range]pyf[ile] {file}

Ejemplo:

:pyfile myscript.py

Simyscript.pynecesitara parámetros la forma de pasárselos es la siguiente:

:py import sys
:py sys.argv = ['foo', 'bar']
:pyf myscript.py

El módulo vim

La comunicación entre Python y Vim se realiza a través del módulo vim, el cual hay que importar antes de usar:

:python import vim

Como indica la ayuda de Vim, el módulo implementa dos métodos (vim.command(str)yvim.eval(str)), tres constantes (vim.buffers,vim.windowsyvim.current) y un objeto error (vim.error). Las tres constantes mencionadas no son realmente constantes sino variables que pueden ser reasignadas pero, como dice también la ayuda, esto sería absurdo ya que se perdería acceso a los objetos de Vim que referencian. Por otra parte cabe recordar que no existen constantes en Python. Como cita el libro "Inmersión en Python":

Todo puede cambiar si lo intenta con ahínco. Esto se ajusta a uno de los principios básicos de Python: los comportamientos inadecuados sólo deben desaconsejarse, no prohibirse.


Read more »

Tags: , ,

Sincronizar Motorola Q y Evolution con SynCE y MultiSync en Ubuntu Jaunty

Para sincronizar contactos, calendario y tareas entre un Motorola Q y Evolution se necesitan dos programas: SynCE y MultiSync.

Como dice el sitio web de SynCE, el objetivo del proyecto es proporcionar un medio de comunicación entre un dispositivo con Windows Mobile y un equipo con Linux, *BSD u otro UNIX, mediante una conexión USB o Bluetooth. Esto permite utilizar la PC para navegar el sistema de archivos del teléfono e instalar aplicaciones y proporciona el medio de comunicación para que mediante otro programa (MultiSync) sea posible sincronizar contactos, calendario y tareas entre el teléfono y una aplicación PIM de escritorio como Evolution.

MultiSync es una herramienta de software libre que sincroniza calendarios, libretas de direcciones y otra información PIM, entre programas de una PC o de otras PC, dispositivos móviles o teléfonos móviles. Depende del framework de desarrollo OpenSync.


Read more »

Tags: ,

umask

Umask (user mask) es un número octal que UNIX utiliza para determinar qué permisos NO asignar automáticamente a los nuevos archivos y directorios creados. Umask sólo restringe permisos; no concede permisos adicionales más allá de lo especificado por defecto.

La mayoría de los sistemas UNIX especifican el valor octal 666 (rw-rw-rw-) para la creación de archivos y el valor octal 777 (rwxrwxrwx) para la creación de directorios. Luego, el kernel utiliza el valor de umask asignado al usuario como máscara para quitar permisos a los definidos por defecto. Todo proceso tiene su umask, heredado del proceso padre del cual desciende.

Los valores más comunes para umask son 022, 027 y 077.
Normalmente el valor de umask se define en /etc/profile

# Set the user's umask
umask 022

aunque es posible setearlo en algún archivo de sesión como ~/.bash_profile, e incluso manualmente para la sessión actual. En todos los casos se utiliza el comando umask que es una función interna de Bash, y de otros shells como ksh y csh. (Si umask fuera un programa separado del shell no podríamos cambiar el valor de umask del proceso shell actual).

Cálculo de permisos

Los permisos de creación se obtienen realizando un AND binario entre el permiso por defecto y el complemento unario (NOT binario) de umask:

Suponiendo que quisiéramos averiguar los permisos de creación de archivos y directorios para umask 027:

permisos archivos:    666 & ~027
permisos directorios: 777 & ~027

Recordemos que el complemento unario puede obtenerse fácilmente reemplazando ceros por unos y unos por ceros:

Complemento unario:
 027 = 000 010 111
~027 = 111 101 000

Luego de obtener el complemento unario se procede a realizar el AND binario:

Archivos:
 666 = 110 110 110
~027 = 111 101 000
------------------
 640 = 110 100 000  <-- (rw-r-----)
Directorios:
 777 = 111 111 111
~027 = 111 101 000
------------------
 750 = 111 101 000  <-- (rwxr-x---)

En bash

$ umask 027
$ mkdir foo
$ touch bar
$ ls -l
drwxr-x---  2 xleo xleo    48 2009-08-19 01:09 foo
-rw-r-----  1 xleo xleo     0 2009-08-19 01:10 bar

Referencias

Tags: ,

Humor en comentarios de códigos fuente

Visto en stackoverflow.com

Algunos de ellos:

// sometimes I believe compiler ignores
// all my comments
// When I wrote this, only God and I understood
// what I was doing. Now, God only knows
if (/*you*/ $_GET['action']) { //celebrate
//
// Dear maintainer:
//
// Once you are done trying to 'optimize'
// this routine, and have realized what
// a terrible mistake that was, please
// increment the following counter as a
// warning to the next guy:
//
// total_hours_wasted_here = 16
//
// I'm sorry.
virgin = 0; /* you're not a virgin anymore, sweety */
... or die // bitch
// This is crap code but it's 3 a.m. and
// I need to get this working.
// Hard to explain

Tags: ,

Calculadora de notación polaca inversa en C

La Notación Polaca Inversa (RPN en inglés, Reverse Polish Notation) es un método de introducción de datos alternativo al algebráico. Fue creada en 1920 por el matemático polaco Jan Lukasiewicz como una forma de escribir expresiones matemáticas sin tener que utilizar paréntesis y corchetes.

En la notación polaca inversa los operadores suceden a sus operandos. Por ejemplo, la expresión algebráica5+((1+2)*4)-3se traduce a la notación polaca inversa como5 1 2 + 4 * + 3 -.

Su principio es el de evaluar los datos directamente cuando se introducen y manejarlos dentro de una estructura LIFO (Last In First Out), lo que optimiza los procesos a la hora de programar.

El siguiente programa es una implementación en C de una calculadora que funciona con notación polaca inversa. El programa es una versión modificada del que figura en el libro “El lenguaje de programación C” de Kernighan y Ritchie.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
## ************
## @file calc.c
## ************

#include <stdio .h>
#include <stdlib .h>

#define MAXVAL 100
#define NUMBER '0'

/**
 *  Variables
 */

int verbose;
int sp = 0;
double val[MAXVAL];

/**
 *  Prototypes
 */

int toi (char const *s);
void push (double);
double pop (void);

/**
 *  Main
 */

int main (int argc, char const *argv[])
{
  int offset, i;
  double op2;

  if (argc < 2)
  {
    fprintf (stderr,
      "Usage: %s [-v] EXP\n", argv[0]);
    return 1;
  }

  verbose = offset =
    (strcmp (argv[1], "-v") == 0) ? 1 : 0;
 
  for (i = 1 + offset; i < argc; i++)
  {
    switch (toi (argv[i]))
    {
      case '+' :
        if (verbose)
          printf ("operator +\n");
        push (pop() + pop());
        break;
      case '-' :
        if (verbose)
          printf ("operator -\n");
        op2 = pop();
        push (pop() - op2);
        break;
      case '*' :
        if (verbose)
          printf ("operator *\n");
        push (pop() * pop());
        break;
      case '/' :
        if (verbose)
          printf ("operator /\n");
        op2 = pop();
        if (op2 != 0.0)
          push (pop() / op2);
        else
          fprintf (stderr,
            "Error: division by zero\n");
        break;
      case NUMBER :
        push (atof (argv[i]));
        break;
      default :
        fprintf (stderr,
          "Error: unknown operator %s\n",
          argv[i]);
        break;
       
    }
  }

  // Result
  printf ("%f\n", val[0]);

  return 0;

}

/**
 *  Toi
 */

int toi (char const *s)
{
  return (isdigit(s[0])) ?
    NUMBER : (int) s[0];
}

/**
 *  Push
 */

void push (double e)
{
  if (sp < MAXVAL)
  {
    if (verbose)
      printf ("push %f in %d\n", e, sp);
    val[sp++] = e;
  }
  else
    fprintf (stderr, "Error: full stack\n");
}

/**
 *  Pop
 */

double pop (void)
{
  if (sp > 0)
  {
    --sp;
    if (verbose)
      printf ("pop %f from %d\n", val[sp], sp);
    return val[sp];
  }
  else
  {
    fprintf (stderr, "Error: empty stack\n");
    return 0.0;
  }
}
</stdlib></stdio>

Para compilarlo ejecutamos

$ gcc -o calc calc.c

A diferencia del programa original publicado en el libro de C, aquí se utiliza el arrayargv[]como fuente de operandos y operadores. Esto permite que podamos llamar al programa desde línea de comandos de la siguiente manera:

$ ./calc 5 1 2 + 4 \* + 3 -

Notar que para el caso especial del operador multiplicación, debemos escaparlo para evitar la expansión propia de bash antes de la llamada efectiva al programa.

El programa admite la opción-v(verbose), que muestra información acerca de uno de los pasos realizados.

Ejemplo I

$ ./calc -v 5 1 2 + 4 \* + 3 -
push 5.000000 in 0
push 1.000000 in 1
push 2.000000 in 2
operator +
pop 2.000000 from 2
pop 1.000000 from 1
push 3.000000 in 1
push 4.000000 in 2
operator *
pop 4.000000 from 2
pop 3.000000 from 1
push 12.000000 in 1
operator +
pop 12.000000 from 1
pop 5.000000 from 0
push 17.000000 in 0
push 3.000000 in 1
operator -
pop 3.000000 from 1
pop 17.000000 from 0
push 14.000000 in 0
14.000000


Read more »

Tags: ,

Tiempos de ejecución de un proceso

Traducción de What do ‘real’, ‘user’ and ‘sys’ mean in the output of time?

$ time foo
real  0m13.520s
user  0m1.628s
sys   0m1.420s
Real
Tiempo real transcurrido desde que el proceso comienza hasta que finaliza. Esto implica el tiempo utilizado por otros procesos ejecutándose al mismo tiempo y el tiempo en que el proceso se encuentra bloquedo (por ejemplo, esperando que una llamada al sistema como I/O se complete).
User
Tiempo de CPU empleado por el proceso en modo usuario (fuera del núcleo). El tiempo de CPU de otros procesos y el tiempo de espera de una llamada al sistema no cuentan en este valor.
Sys
Tiempo empleado por el núcleo para atender peticiones del proceso. Esto significa tiempo de uso de CPU en llamadas al sistema dentro del núcleo, como por ejemplo I/O.

User+Sys equivale al total de tiempo de CPU usado por el proceso.


Read more »

Tags:

Snippets en Vim con snipMate

Basado en el editor TextMate (mac), snipMate.vim es un plugin que permite insertar pedazos de código de uso frecuente simplemente tipeando parte del mismo y apretando<tab>.

Por ejemplo, supongamos que estamos editando un programa en C y queremos agregar un ciclo for, simplemente escribimosfor<tab>y esto se expandirá en un típico bucle de C

for (i = 0; i < count; i++)
{
    /* code */
}

Inmediatamente después el cursor quedará resaltando la palabra “count” para que podamos reemplazarla por nuestra condición de fin. Un par de tabs más nos llevarán al cuerpo del ciclo donde podremos seguir utlizando snippets comopr<tab>, lo que expandirá en la función printf

for (i = 0; i < 10; i++)
{
    printf("%s\n");
}

snipMate tiene una sintáxis muy sencilla (según dicen, muy similar a la usada por TextMate) lo que permite crear nuestros propios snippets, o mejorar los existentes. La versión actual (0.77) trae una colección de snippets para los siguientes lenguajes: C, Obj-C, C++, Sh, TeX, Java, Ruby, Perl, Python, PHP, JavaScript, y HTML.

El proyecto parace estar bastante activo y la última versión es del 30/03/2009.

Tags:

Accediendo a MySQL con Python y MySQLdb

MySQLdb es un módulo que implementa la API estándar (PEP249) para manejo de bases de datos, en este caso MySQL. MySQLdb es en realidad un wrapper del módulo _mysql que provee Python, el cual implementa la mayoría de las funciones definidas en la API C de MySQL. La idea de definir una API estándar es que uno debería poder cambiar a otra base de datos sin modificar demasiado el código.

This API has been defined to encourage similarity between the Python modules that are used to access databases.

Instalación MySQLdb

El paquete que nos provee el módulo se llama python-mysqldb. Podemos comprobar que lo tenemos instalado mediante

dpkg --get-selections | grep python-mysqldb

Si no existe lo instalamos

sudo apt-get install python-mysqldb

Para comprobar que efectivamente tenemos el módulo disponible y funcionando llamamos al intérprete de Python y escribimos

>>> import MySQLdb

Un silencioso retorno de carro indica que podemos el módulo ha sido cargado. Salimos del intérprete conC-d.

Creación de una DB de pruebas

Para nuestro ejemplo crearemos una base de datos con una única tabla. Entramos a la consola de MySQL y escribimos

mysql> CREATE database test;
Query OK, 1 row affected (0.01 sec)

mysql> USE test;
Database changed
mysql> CREATE TABLE users (
    -> id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    -> name VARCHAR(100),
    -> lastname VARCHAR(100)
    -> );
Query OK, 0 rows affected (0.01 sec)

mysql> INSERT INTO users (name, lastname) VALUES
    -> ('Juan', 'Perez'),
    -> ('Ana Maria', 'Lopez'),
    -> ('Carlos L.', 'Gutierrez');
Query OK, 3 rows affected (0.00 sec)
Records: 3  Duplicates: 0  Warnings: 0

Nuestra tabla users quedó entonces

mysql> SELECT * FROM users;
+----+-----------+-----------+
| id | name      | lastname  |
+----+-----------+-----------+
|  1 | Juan      | Perez     |
|  2 | Ana Maria | Lopez     |
|  3 | Carlos L. | Gutierrez |
+----+-----------+-----------+
3 rows in set (0.00 sec)

Creación del script mysqldb.py

Creamos el siguiente script que se conectará a la base de datos test y traerá todos los datos de los usuarios cargados en la tabla users. En el script es necesario reemplazar <user> y <pass> por los datos requeridos para acceder a tu DB.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#!/usr/bin/python
import MySQLdb

# Conexion a la base de datos
conn = MySQLdb.connect (host="localhost",
    user="<user>", passwd="<pass>", db="test")

# Creacion cursor
cursor = conn.cursor()

# Ejecucion query
cursor.execute("SELECT * FROM users")

# Manejo de datos devueltos por la consulta
while True:
    row = cursor.fetchone()
    if row is None:
        break
    else:
        print "id: %s\tname: %s %s" %
            (row[0], row[1], row[2])

# Finalizado cursor y objeto conexion
cursor.close()
conn.close()

La salida debería ser

id: 1   name: Juan Perez
id: 2   name: Ana Maria Lopez
id: 3   name: Carlos L. Gutierrez

Links recomendados para ampliar conocimientos

Tags: , ,