Automágica: durante 2017 estoy trabajando bastante en Automágica, mi software para editar libros: Más información - Posts relacionados

En borrador permanente

Le acabo de cambiar el nombre a mi blog. Pasó de "Vientos de Libertad" a "En borrador permanente". El nombre original hacía alusión al Software Libre; pensaba escribir principalmente sobre eso. No pasó.

Este nuevo nombre hace referencia a un sentimiento que me invade cada vez que le doy al botón "publicar": esto es basura. Me cuesta mucho estar conforme con lo que publico; es por eso que siempre está "En borrador permanente". Be my guest.

Imagen de Wikemedia Commons.

Si esperara a que estén listos, muchos de los posts de este blog nunca hubiesen sido publicados.


La última lección (libro)

Esta semana terminé de leer La última lección. Si bien suelo leer libros técnicos o ficciones, este libro no es ninguno de ambos. No es ficción, pero cuenta una historia; y está escrito por un científico, pero no es un libro técnico.

El libro te sacude desde el arranque:

Tengo un problema de ingeniería. A pesar de que, en su mayor parte, estoy en excelente condición física, tengo diez tumores en el hígado y me restan unos cuantos meses de vida.

El autor, Randy Pausch, profesor de Canegie Mellon, fue un científico de la computación especializado en interacción hombre-máquina, uno de los creadores del lenguaje de programación Alice, a quien en el año 2006 le diagnosticaron cáncer de páncreas. A partir de ahí empezó a ordernar sus cosas para irse tranquilo (tenía una mujer y 3 hijos). En eso lo invitan a dar una clase o charla llamada La última lección en su universidad; en esta les plantean a los profesores qué enseñarían si estuvieran muriendo y podrían dar una última lección. Para Randy era de verdad.

Su última lección se llamó algo así como Cumple los sueños de tu infancia, y causó bastante conmoción. Puede verse on line. Uno de los asistentes fue el periodista Jeffrey Zaslow junto con quien escribió el libro basado en La última lección. La forma de escribirlo fue bastante peculiar, Randy tenía que hacer ejercicio todas las mañanas (como un paliativo para su enfermedad) y mientras ejercitaba, se comunicaba con un teléfono celular manos libres con Jeffrey contándole las historias que se convirtieron en los capítulos del libro.

El libro está muy bueno y vale la pena leerlo; lo recomiendo. Cuando lo compré, no sabía que el autor era informático, por lo que cuando lo leía encontré algunos giros y menciones que me divirtieron de formas que no-informáticos no entendería; como gancho para mis amigos nerds: a lo largo de los capítulos se menciona a Wikipedia, Google y Python.


El hosting para Django más barato

Hace un tiempo recomendé Webfaction como el mejor hosting para Django (debe aún serlo). Pero algunas veces no queremos el mejor, con el más barato nos alcanza :D

Tal vez son un adolecente aprendiendo a programar, o simplemente rata. Para un programador PHP es bastante fácil encontrar un hosting en Internet que le de un servicio gratuito, subir sus cosas y mostrarlas al mundo. Cuando programás en Django... es más difícil.

Hasta hoy; les paso el dato: AlwaysData.com

Hosting Django gratuito.

Tengo 2 cuentas funcionando muy bien. Y no se asusten por que está en francés (eso me detuvo la primer vez que lo vi); luego de sacar la cuenta tenés acceso al panel de administración que está en muchos idiomas; incluyendo español. Tenés para elegir distintas versiones de Python y Djando, MySQL o PosgreSQL, acceso SHELL, FTP y WebDAV. Qué más querés?

También podés tener PHP o Ruby on Rails.

Espero les sirva.


Borges hacker

Dijo nuestro escritor por excelencia:

"Uno llega a ser grande por lo que lee y no por lo que escribe."

BORGES, Jorge Luis

Escritor argentino.

Años más tarde, desde los más oscuros rincones de la web 2.0 y las redes sociales, el espíritu del poeta infunde a la juventud. Distinto oficio, misma verdad:

Los mejores programadores no son los que más código escriben, sino los que más código leen. @alejolp


Lo que todo programdor debería saber sobre...

Hace un par de días hablábamos con una compañera sobre NO USAR el tipo de datos float para manejar dinero:

>>> 0.1 + 0.3

0.40000000000000002

A no alarmarse, lo anterior sucede en todos los lenguajes de programación; aunque algunos lo ocultan más que otros. La charla terminó con la recomendación de revisar un sitio web que explica el tema de forma muy consisa:

What Every Programmer Should Know About Floating-Point Arithmetic

Además de explicar cómo funciona el tipo de datos float y cómo solucionar el problema, da machetes para varios lenguajes de programación (C#, Java, JavaScript, PHP y SQL).

Me sorprendió que no haya una para Python, por lo que seguí el mandato del autor del sitio web, fork me on github, y envié mis cambios. update: ya está disponible en el sitio web.

Siguiendo con el título del posts, me puse a buscar otros artículos con el formato: Lo que todo programador debería saber sobre... y encontré estos:


Salió la revista de PyAr

Hoy salió a la calle (del cyberespacio) el número 1 de PET, Python Entre Todos, la revista de la comunidad Python Argentina.

Cuando empezaron a organizarla no tenía tiempo para prestarle mucha atención, pero un par de semanas antes de que esté lista pude colaborar un poco más y mandé un artículo sobre Taint Mode, un desafío y e hice un poquito de revisor. Espero en la próxima edición colaborar un poco más; en esta primera vuelta todo el trabajo de edición recayó sobre Roberto Alsina y Emiliano Dalla Verde Marcozzi.

Destaco hasta ahora de los que leí, un artículo sobre la historia del grupo, pero tengo muchos más en la cola de lectura!

¿Qué hacés que todavía no fuiste a leer? Está disponible en varios formatos!



argparse - Command line option and argument parsing

Hoy recibí la última edición de Python Module of the Week, un semanal de Doug Hellmann sobre módulos de Python. Leo:

The argparse module was added to Python 2.7 as a replacement

for optparse.

Nunca había usando optparse hasta hace un par de meses y estaba contento de haberlo empezado a usar, ordenaba mis programas de línea de comando con bonitos parámetros. ¿Tengo que aprender otro sistema totalmente nuevo? Veamos.

Esta es una parte de mi programa original:

from optparse import OptionParser

parser = OptionParser(usage="rpcping ip [-p port] [-r rep] [-s size]", version="rpcping 1.0")



parser.add_option("-p", type="int", dest="port", default=PORT)

parser.add_option("-r", type="int", dest="rep", default=REP)

parser.add_option("-s", type="int", dest="size", default=SIZE)

(options, args) = parser.parse_args()



if not args:

    parser.error("se necesita la direccion ip del servidor como argumento posicional.")

else:

    ip = args[0]



if not 1024 < options.port < 65535:

    parser.error("el puerto debe ser mayor a 1024 y menor a 65535.")

else:

    port = options.port



if not 0 < options.rep < 101:

    parser.error("las repeticiones deben ser mayores a 0 y menores a 101.")

else:

    rep = options.rep



if not 0 < options.size < 10001:

    parser.error("el tamaño deben ser mayores a 0 y menores a 10001.")

else:

    size = options.size

Qué tuve que cambiar para que funcione con argparse:

  • Cambiar nombres; optparse por argparse, OptionParser por ArgumentParser, add_option por add_argument.
  • Cambiar el valor del agumento type de string a un tipo de verdad. En mi caso type="int" por type=int.
  • Si tratamos de obtener el resultado del parsing así (options, args) = parser.parse_args(), vamos a tener un error TypeError: 'Namespace' object is not iterable. El nombre result en el nuevo código está asociado a un objeto del tipo Namespace.
  • optparse no trabaja con argumentos obligatorios, por lo que para el argumento ip había tenido que escribir código extra por mi cuenta. En argparse es más simple.

El resultado es:

from argparse import ArgumentParser

parser = ArgumentParser(description="Realiza ping via RPC contra un servidor", version="rpcping 1.0")



parser.add_argument("ip")

parser.add_argument("-p", type=int, dest="port", default=PORT)

parser.add_argument("-r", type=int, dest="rep", default=REP)

parser.add_argument("-s", type=int, dest="size", default=SIZE)

result = parser.parse_args()



ip = result.ip



if not 1024 < result.port < 65535:

    parser.error("el puerto debe ser mayor a 1024 y menor a 65535.")

else:

    port = result.port



if not 0 < result.rep < 101:

    result.error("las repeticiones deben ser mayores a 0 y menores a 101.")

else:

    rep = result.rep



if not 0 < result.size < 10001:

    parser.error("el tamaño deben ser mayores a 0 y menores a 10001.")

else:

    size = result.size

Parece que con poco esfuerzo se puede migrar de optparse a argparse y luego empezar a estudiar las nuevas funcionalidades que incorpora.

The implementation of argparse supports features that would not have been easy to add to optparse, and that would have required backwards-incompatible API changes, so a new module was brought into the library instead. optparse is still supported, but is not likely to receive new features.

Más en: PyMOTW: argparse - Command line option and argument parsing.


functools.update_wrapper

Este post se alinea con la serie Decoradores en Python (I, II, III) pero no es tan elaborado como para ser Decoradores en Python (IV) :)

Desde Python 2.5, al crear un decorador, se puede utilizar functools.update_wrapper para quela versión decorada de la función, tenga los atributos name, doc, module y dict de la función original.

>>> import functools

>>> def deco(f):

... def inner(a, *kw):

... print "Este decorador no hace nada"

... return f(a, *kw)

... return inner

...

>>> def saludo():

... print "hola"

...

>>> saludo2 = deco(saludo)

>>> saludo2()

Este decorador no hace nada

hola

>>> saludo2.name

'inner'

>>> def deco(f):

... def inner(a, *kw):

... print "Este decorador no hace nada"

... return f(a, *kw)

... return functools.update_wrapper(inner, f)

...

>>> saludo3 = deco(saludo)

>>> saludo3()

Este decorador no hace nada

hola

>>> saludo3.name

'saludo'

>>> saludo = saludo3


Puedo disfrazar cualquier cosa de Modbus

Hace más de un año participo en un proyecto de desarrollo de un sistema SCADA, específicamente en la capa de comunicación. La distribución física es algo como esto:

En cada edificio hay una red 485 con dispositivos de hardware propio (aka Robot) y un módulo celular (Motorolla G24) con salida a Internet vía GPRS. Esos módulos se registran en un servidor (escrito con Twisted) para ser luego sondeados: se registran sus mediciones, hay gráficos en tiempo real, se puede hacer telecomando y encender un equipo a la distancia o cambiar un set point; entre otras cosas.

Nuestra primera implementación estaba inspirada en el protocolo Modbus ASCII, pero bastante alejada del estándar. Nos sirvió por bastante tiempo y no apegarnos a una especificación nos permitió acelerar el desarrollo; especialmente del hardware.

Modbus es un protocolo de línea maestro/esclavo en donde el maestro realiza peticiones de lectura o escritura sobre algún o algunos registros en un esclavo. El protocolo define 4 tipos de registros (analógicos o digitales, de solo lectura o lectura-escritura) y fue pensado para funcionar sobre una línea serie; existen dos sabores: RTU, dónde los datos viajan en forma binaria y la ocupación del canal es optimizada y ASCII, menos eficiente pero legible por humanos. Se puedo leer más al respecto en Wikipedia o en la página oficial del protocolo.

Hace algunos meses empezamos a utilizar Mango m2m. Mango tiene todos los componentes de interfaz de usuario que se pueden necesitar en un SCADA en adición a la posibilidad de conectarle distintas fuentes de datos (desde Modbus Serie a un motor de base de datos); las más interesante para nosotros es Modbus TCP.

Modbus TCP extiende el protocolo original para poder utilizarlo sobre la red de redes en lugar de sobre una línea serie. Por ejemplo, una de las cosas que hace es agregar al paquete enviado un número consecutivo para solucionar el problema de paquetes perdidos o duplicados.

Teníamos entonces, por un lado Mango que sabe hablar Modbus TCP y por el otro los robotitos hablando un dialecto de Modbus ASCII. En el medio, el servidor de comunicaciones. La pregunta en este punto era cómo unir ambos extremos, de manera de aprovechar esta herramienta que soluciona muchos de nuestros requerimientos.

Allí es donde entra en acción pymodbus, una implementación en Python del stack Modbus. No solo está escrita en Python, sino que está implementada utilizando el framework Twisted, el mismo que venía usando para el servidor de comunicaciones. Utilizando pymodbus pude engañar a Mango y hacerle creer que hablaba contar dispositivos Modbus TCP cuando en realidad interceptaba sus peticiones, enviaba los comandos necesarios a los robots y contestaba con la respuesta correcta.

En el camino encontré varios problemas en la librería, los fui reportando y enviando parches para solucionarlos. A lo último eran tanto los cambios que enviaba y empecé a modificar el core de la librería para que funcione con deferrers (es decir, siguiendo la filosofía de Twisted) que recibí permiso de commit en la rama devel.

Nota: el esquema descripto funcionó bastante tiempo. Actualmente seguimos avanzando y los robots ya hablan Modbus ASCII estándar a la vez que el componente intermedio adelgazó para convertirse en un traductor o gateway.