Manuel Kaufmann (Humitos): Crear GIFs de comandos en terminal

   Publicado:

Hace un tiempo que tengo curiosidad por saber cómo crean esos "screencast" de los comandos que van tipeando en una terminal y los meten en un blog en formato gif.

Hoy encontré ttygif que te deja crear un GIF a partir de lo grabado con ttyrec -que basicamente permite grabar los comandos que vas tipeando en la consola y luego reproducirlo con el comando ttyplay.

Bueno ttygif mientras lo va reproduciendo va grabando una pequeña imagen de lo que se va mostrando junto con un tiempo en milisegundos. Luego, ejecutando su comando concat.sh te permite guardar eso en un gif.

Para instalarlo:

sudo apt-get install imagemagick ttyrec gcc
git clone https://github.com/icholy/ttygif
cd ttygif
make

Para usarlo:

ttyrec fades-django
./ttygif fades-django
./concat.sh fades-django.gif

¡Listo!

Aquí en el resultado, muestro fades con Django:

fades-django.gif

Manuel Kaufmann (Humitos): Actualizar a una versión nueva de Nikola

   Publicado:

Nikola es un generador de sitios web estáticos que está buenísimo. Además, es el que uso para mantener este blog y el sitio web de Argentina en Python de una forma sencilla y sin mucho esfuerzo, que me permite focalizarme en el contenido sin molestarme en recursos de máquina, base de datos y otros dolores de cabeza. Además, como trabaja con reStructuredText me permite aprovechar todo su poder.

Como decía, es muy simple. Y así también lo es su actualización:

pip install -U nikola

Sin embargo, si tenés un custom theme y querés beneficiarte de los cambios en el tema del que heredás (yo me baso en bootstrap3) es necesario hacer un paso extra. Ese paso extra consiste en ver las diferencias de los templates que nosotros hemos modificado con respecto al tema heredado contra los originales y agregar los cambios que sean necesarios/compatibles. Para eso yo uso meld:

meld nikola-git-repo/nikola/data/themes/bootstrap3/templates themes/elblogdehumitos/templates

Y luego contra el theme del que hereda bootstrap3 que es base:

meld nikola-git-repo/nikola/data/themes/base/templates themes/elblogdehumitos/templates

De esa forma controlo las diferencias que haga falta y voy copiando hacia mis templates las que me benefician.

Por último, es posible que hayan agregado algunas características nuevas que requieran alguna configuración extra. Para saber cuáles son esas configuraciones podemos leer el CHANGES.txt para buscar algo puntal y agregar la que necesitemos, o bien podemos hacer un proyecto demo (con la última versión de Nikola instalada) y comparar su archivo conf.py:

nikola version
nikola init --demo -q /tmp/nikola-demo
meld /tmp/nikola-demo/conf.py conf.py

¡Ahora sí! Tenemos nuestro sitio Nikola actualizado a la última versión disponible.

Marcos Dione: ayrton-0.7.1

   Publicado:

A weird release, written from Russia via ssh on a tablet. The changelog is enough to show what's new:

  • Iterable parameters to executables are expanded in situ, so foo(..., i, ...) is expanded to foo (..., i[0], i[1], ... and foo (..., k=i, ...) is expanded to foo (..., k=i[0], k=i[1], ....
  • -x|--trace allows for minimal execution tracing.
  • -xx|--trace-with-linenos allows for execution tracing that also prints the line number.

Get it on github or pypi!


python ayrton

Manuel Kaufmann (Humitos): Maneja los archivos requirements con pip-tools

   Publicado:

El tema de los paquetes de Python, es un tema. Normalmente yo instalo los paquetes que necesto a mano con pip install, eso a su vez me instala un montón de dependencias. Luego, pinneo los paquetes que uso en el proyecto haciendo pip freeze para que luego esa instalación sea reproducible en otro equipo.

Sin embargo, con esto te perdés de un montón de cosas. Sobre todo, las actualizaciones de las dependencias de los paquetes que instalaste a mano. Vincent Driessen lo explica mucho mejor que yo en su blog post: Pin Your Packages.

Para facilitarnos esta tarea, este flaco Vincent creó la herramienta llamada pip-tools que soluciona este problema entre otros.

Básicamente consiste en dos herramientas: pip-compile y pip-sync.

Para poder mantener en orden nuestro entorno virtual y que todo vaya de forma correcta y actualizada, debemos crear un archivo requirements.in que será donde indicamos qué paquetes necesitamos. Por ejemplo en un proyecto que necesitemos Django y django-phonenumber-field:

# requirements.in
Django
django-phonenumber-field

y luego:

$ pip-compile
#
# This file is autogenerated by pip-compile
# Make changes in requirements.in, then run this to update:
#
#    pip-compile requirements.in
#

babel==2.2.0              # via django-phonenumber-field
django-phonenumber-field==1.0.0
Django==1.9.2
phonenumbers==7.2.4       # via django-phonenumber-field
pytz==2015.7              # via babel

Este comando nos va a generar nuestro archivo requirements.txt con todas las versiones de los paquetes necesarios, y sus dependecias, pinneados como corresponde. Pero además, cada una de esas dependencias tendrá un comentario que va a indicar porqué es necesaria o de dónde viene.

Finalmente, para poner a tiro nuestro entorno e instalar todas los requerimientos necesarios con esas versiones específicas, ejecutamos:

pip-sync

Pasan los días, las semanas y los meses. Salen nuevas versiones de los paquetes y no nos enteramos. Ahí volvemos a utilizar el comando pip-compile para que compruebe todos los paquetes necesarios y se fije si hay una nueva versión y demás. Crea nuevamente el requirements.txt y si vemos que queremos actualizar todos esos paquetes, hacemos un pip-sync.

¡De puta madre pip-tools!

Manuel Kaufmann (Humitos): Historial de seguidores en Twitter

   Publicado:

Desde que empecé a usar Twitter de forma activa me llamó mucho la atención cómo funciona, pero no técnicamente, sino más bien en lo social. El alcance que tiene a poder ver el contenido de casi cualquier persona y hacer re-tuits de personas a las que no seguís. De hecho, gracias a ese feature hemos podido llegar a muchos más lugares con el proyecto.

Si bien no he podido dedicarme mucho tiempo a escribir algunos scripts que hagan este análisis por mí, comencé con algo simple: el historial de seguidores.

¿Cómo es eso? La idea es poder saber quienes te siguen, quién es un nuevo seguidor y quién te dejó de seguir. Claramente, los últimos son los más importantes para evaluar: ¿porqué perdí a este seguidor? es la pregunta del millón.

El problema se dividió -automáticamente, en dos partes. La primera: obtener todos los seguidores de la cuenta @argenpython de forma periódica. La segunda: hacer diff de esos seguidores de forma incremental. ¿Qué quiero decir con incremental? Que no necesito saber la diferencia entre el primer reporte y el último, porque si en los reportes del medio alguien me empezó a seguir y luego me dejó de seguir, también quiero saberlo.

La obtención de los seguidores lo resolví con este pequeño script (en un @daily de CRON):

fades -d twitter -x twitter-follow --oauth argenpython > argenpython.followers_`date +"\%Y\%m\%d"`.txt

Para hacer la diferencia de todos esos seguidores recolectados diariamente con el script anterior, "escribí" [1] un script en Python:

listings/historial-de-seguidores-en-twitter/multiplediff.py

import difflib
import os


def get_files():
    return sorted([f for f in os.listdir() if f.startswith('argenpython.followers_')])


def get_date(filename):
    return filename[:-4].split('_')[1]


def get_diff(old, new):
    # Since Twitter API doesn't give as the followers list sorted, we
    # need to sorted it because if not there will be removed and added users
    # with the same name between 2 different files
    old_lines = sorted(open(old).readlines())
    new_lines = sorted(open(new).readlines())
    return ''.join(difflib.unified_diff(old_lines, new_lines))


def compare_files():
    files = get_files()
    olds = ['/dev/null'] + files[:-1]
    for old, new in zip(olds, files):
        print('Changes in', get_date(new))
        print(get_diff(old, new))

if __name__ == '__main__':
    compare_files()

Finalmente, para saber cuáles son los seguidores que hemos perdido en el camino utilicé este comando de bash:

python3 multiplediff.py | grep "^-b" | wc -l

Eso me arrojó 39 como resultado. Por lo tanto, como este script está corriendo desde el 1 de Enero de 2016, puedo decir que hemos perdido 39 seguidores en este mes.

[1]dijo el más mentiroso del mundo, el código me lo pasó Ariel Rossanigo por Twitter, justamente. Yo solo le hice unas pequeñas y mínimas modificaciones.

Manuel Kaufmann (Humitos): Hotkeys for the win

   Publicado:

¿Cuántas aplicaciones utilizás en el día a día? Digamos que nos limitamos a las más comúnes únicamente. En ese caso, mi respuesta sería: 6 (emacs, firefox, terminator, pidgin, thunar y thunderbird)

Esas aplicaciones las tengo abiertas casi todo el día. Además, a medida que voy trabajando comienzo a abrir otras: Google Chrome, LibreOffice, JOSM, gThumb, inkscape, Skype y algunas más. A mitad de la tarde, ¿cuántas aplicaciones tenés abiertas? Y lo más importante: ¿cuántas veces hiciste Alt + TAB? Aunque lo peor de todo es: ¿cuántas veces hiciste Alt + TAB y te pasaste por una ventana y diste toda la vuelta hasta la correcta o bien, te fracturaste un dedo haciendo Alt + Shift + TAB para volver una selección?

Bueno, hace varios años que yo me cansé de eso y decidí buscar una solución. La solución vino exactamente con la primera pregunta que te hice: ¿cuántas aplicaciones utilizás en el día a día?. Básicamente quería poder acceder a cualquiera de esas 6 aplicaciones sin que importara en qué orden las había abierto o había estando navegando por ellas. Digamos, que si fui a firefox, luego a pidgin y luego a thunderbird; quería poder saltar en un solo hotkey a terminator -que si usamos Alt + TAB tendríamos que presionarlo 3 veces consecutivas.

Primero me puse a investigar cómo se puede hacer para cambiar de ventanas utilizando la línea de comandos. Ahí llegué a wmctrl, que te permite listar las ventanas activas y también cambiar entre cada una de ellas mediante una interfaz de línea de comandos.

$ wmctrl -l -x
0x01600003  0 Thunar.Thunar         victoria humitos - Administrador de archivos
0x040000a3  0 emacs.Emacs           victoria emacs-victoria: ~/bin/change-window [-]
0x024000ab  0 Navigator.Firefox     victoria Inbox (0) - someone@gmail.com - Gmail - Mozilla Firefox
0x04200db8  0 Pidgin.Pidgin         victoria (someone@gmail.com)
0x0420006a  0 Pidgin.Pidgin         victoria Lista de amigos
0x03e00001  0 Google-chrome.Google-chrome  victoria Nueva pestana - Google Chrome

Ahora bien, con esa información de WINDOW_ID, NAME y WINDOW_TITLE ya puedo cambiar de una ventana a la otra utilizando su WINDOW_ID así -por ejemplo para ir a la lista de amigos de Pidgin:

$ wmctrl -i -a 0x0420006a

Ahora necesitaba presionar un hotkey y que ejecute algo que parsee esa salida y cambie a la ventana que quiero utilizando wmctrl. La ventana que "quiero" dependerá del hotkey presionado.

Entonces, ¡escribí un script en Python, por supuesto!

listings/hotkeys-for-the-win/change-window

#!/usr/bin/env python

import os
import sys
import commands

LIST_WINDOWS = 'wmctrl -l -x | grep -i {} | grep -v grep | tail -n {}'
CHANGE_WINDOW = 'wmctrl -i -a {}'
COMMANDS_TO_WMCMD = {
    'pidgin': 'Pidgin.Pidgin',
    'emacs': 'emacs.Emacs',
    'thunar': 'Thunar.Thunar',
    'firefox': 'Navigator.Firefox',
    'terminator': 'terminator.Terminator',
}


def get_window_id(command):
    # This function is horrible but it's late at night and I just want
    # this shit working :)
    if command == 'pidgin':
        n = 2
    else:
        n = 1
    output = commands.getoutput(
        LIST_WINDOWS.format(COMMANDS_TO_WMCMD[command], n))
    if n > 1:
        if command == 'pidgin':
            lines = output.splitlines()
            for l in lines:
                if 'Lista de amigos' not in l:
                    output = l
                    break
    print(output)
    win_id = output.split(' ')[0]
    return win_id


def main():
    program = sys.argv[1]
    win_id = get_window_id(program)
    if win_id != '':
        os.system(CHANGE_WINDOW.format(win_id))
    else:
        os.system(program)


if __name__ == '__main__':
    main()

Básicamente hace eso que dijimos. Sin embargo, le agregué una cosita más. A veces pasa que tengo abierta la "Lista de amigos" y una "Ventana de conversación" en Pidgin y necesitaba poder decirle que vaya a la ventana de conversación de alguna forma. Esto es porque cuando estás chateando con alguien querés poder presionar el hotkey, contestarle, presionar el hotkey del emacs y seguir codeando; sin necesidad de pasar por la lista de amigos. Entonces, hace eso: si hay una ventana con "Lista de amigos" en su WINDOW_TITLE, elije la otra que sea de Pidgin :)

Nota

No te olvides de asignarle permisos de ejecución a tu programa python con:

chmod +x change-window

Perfecto, lo único que queda es decirle a nuestro entorno gráfico que cuando presionemos nuestro hotkey maravilla ejecute nuestro programa. Yo uso xfce por lo tanto, tengo que modificar el archivo xml de mi directorio personal ~/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-keyboard-shortcuts.xml y agregar estas líneas en la sección <property name="custom" type="empty">:

<property name="&lt;Super&gt;t" type="string" value="/home/humitos/bin/change-window terminator"/>
<property name="&lt;Super&gt;e" type="string" value="/home/humitos/bin/change-window emacs"/>
<property name="&lt;Super&gt;f" type="string" value="/home/humitos/bin/change-window firefox"/>
<property name="&lt;Super&gt;a" type="string" value="/home/humitos/bin/change-window thunar"/>
<property name="&lt;Super&gt;c" type="string" value="/home/humitos/bin/change-window pidgin"/>

Ahora sí, con Super+t voy a la terminal de Terminator sin importar dónde esté en ese momento. Lo mismo para Super+f, Super+c y demás. Antes de que pestañés, yo ya cambié 5 veces de ventana y siempre exactamente a la que quería ;)

Te aseguro que te vas a ahorar milisegundos con esto. Luego segundos, luego minutos y finalmente unas cuantas horas y puteadas de haberte pasado por uno con el Alt + TAB y tener que dar toda la vuelta cuando tenés 15 ventanas abiertas.

¡Ah! Y una cosa que me olvidaba: si el programa del cual presionamos el hotkey no está abierto, lo abre ;)

Vos, ¿cómo resolvés este problema?

Manuel Kaufmann (Humitos): Aplicando rock a mi Emacs

   Publicado:

Hace tiempo que uso Emacs. Hace no tanto tiempo que lo tengo configurado como me gusta y eso es porque nunca entendí la lógica de elisp, que es lo que se necesita saber para poder configurar algunas variables y hacer unos hook. Sin embargo, con el tiempo le fui agarrando la mano y fui pudiendo instalar a mano un montón de plugins que cada tanto, los actualizaba y alguno de ellos explotaba. Por eso, con el tiempo, se me fueron pasando las ganas de ir buscando nuevas cosas para enchular mi emacs y me dedicaba a utilizarlo como lo había dejado hace algunos años (por lo menos 2).

Anoche me dije: "voy a volver a ver qué cosas nuevas hay para Emacs y actualizar mi entorno de desarrollo". Así fue que llegué a elpy y a un blogpost de realpython.com que está genial.

Aunque no uses Emacs ni te guste, te recomiendo pegarle una mirada a ese post de Real Python ya que te puede dar algunas ideas.

Mucho de lo que cuentan ahí yo ya lo tenía configurado, pero a lo bestia: utilizando hooks y cosas raras para que funcionen y -como no sabía casi nada de elisp, estaba todo atado con alambre y a veces crasheaba como loco. No hay nada peor que estar codeando esa idea que te llevó días poder llegar a tener y que no te funcione tu editor de código como vos querés. En esos momentos, iba deshabilitando los diferentes plugins y así me fui quedando con muy pocos.

Hotkeys

Emacs es un mundo, posta. No estoy seguro si estos hotkeys son específicos de elpy, pero son los que me llamaron la atención y que voy a empezar a usar:

M-down:
M-up:desplaza la región seleccionada una línea hacia arriba o hacia abajo
M-left:
M-right:deplazan la región seleccionada un nivel en la identación hacia la izquierda o la derecha
M-z <char>:borra hasta la primera aparición de <char>
C-c C-f:busca un archivo dentro del proyecto actual (lo adivina con heurística) utilizando un poco de fuzzy
C-c C-s:hace un grep -r en el proyecto actual con lo seleccionado
M-.:va hacia la definición de la función / método / clase sobre la que tenemos el cursor
M-*:vuelve a donde estábamos antes de presionar M-.
C-c C-z:abre un intérprete de Python en un buffer o bien recupera el existente
C-c C-c:manda el buffer actual al intérprete de Python para que lo ejecute
C-c C-d:abre la documentación de Python de la función / método / clase sobre la que tenemos posicionado el cursor
C-c C-t:ejecuta los tests del proyecto
C-c C-r f:formatea el código utilizando yapf o autopep8
C-c C-r i:autoimporta módulos que falten y ordena los que ya están importados

Conclusión

Hay mucha información sobre cómo instalar estas cosas, blog posts y documentación oficial. Yo tengo hecho algo que no recomiendo porque es oldschool y ahora es mucho mejor utilizar paquetes de META.

Les recomiendo que cada tanto le peguen una mirada a la configuración que tienen de su editor de código y vean configuraciones de otros, pero no las copien así nomás, ya que de esa forma van a tener un montón de cosas configuradas que no van a saber usar. Sino que la idea es ir configurando de a poco las cosas que vamos viendo interesante y tratar de sacarle el jugo.

Mi configuración de emacs

Tengo un repositorio en Github con toda la configuración de mi emacs, por si te interesa ver algo en particular: https://github.com/humitos/emacs-configuration

Manuel Kaufmann (Humitos): Audio en RaspberryPi

   Publicado:

La RaspberryPi se convirtió en esa cosa super poderosa que está prendida todo el tiempo y que brinda un montón de servicios. Sí, ¿para qué tener prendida mi notebook para ver un video? Para eso está kodi. ¿Para qué voy a tener un router y configurarlo extensivamente y así y todo que no sirva todo lo que quiero? Para eso está pyfispot. Y, finalmente, ¿para qué voy a tener la pc prendida solo para escuchar música? Para eso está mplayer y mps-youtube.

IMG_20160208_144255.thumbnail.jpg

La RaspberryPi colgada, como siempre...

Cuando utilizo kodi siempre lo hago conectado a un TV con entrada de HDMI, así el video y el audio se configuran solo sin ningún problema. Luego manejo todo desde el celular con yatse. Sin embargo, a veces -como ahora- no tenemos un televisor pero sí queremos escuchar música como si estuviésemos con kodi: nuestras notebooks apagadas pero la raspi reproduciendo música. Ok, instalé mplayer para eso y pude reproducir la música que tengo localmente en la raspi sin problemas. Lo único que tuve que hacer fue decirle a la raspi que quiero utilizar el Audio Jack Analógico y no el HDMI:

sudo amixer cset numid=3 1

Luego le doy permisos para usar el audio a mi usuario:

sudo usermod -G audio -a alarm

Sin embargo, como dije antes, esto me permite escuchar sólo la música que tengo localmente y con kodi nosotros escuchábamos música de YouTube también. Ahí es que llegué a mps-youtube, lo instalé y ya lo estoy usando:

~/fades/bin/fades -d mps-youtube -x mpsyt

No hace falta que diga nada más. Es muy fácil de usar y tiene una ayuda integrada.

Versión obsoleta en Ubuntu 14.04

Si estás utilizando la versión LTS de Ubuntu, es probable que tengas una version obsoleta de mplayer, por lo que debes actualizarla. Sin embargo, en mi máquina no actualiza a una versión capaz de funciona correctamente con mpsyt por lo tanto instalé mpv y lo configué en mpsyt con este comando:

set player mpv

Juanjo Conti: Narrar es...

   Publicado:
“Narrar es como jugar al póker. Todo el secreto consiste en parecer mentiroso cuando se está diciendo la verdad.”

― Ricardo Piglia.

Juanjo Conti: Agroecología

   Publicado:
La Agroecología plantea que la mejor opción es compartir la tierra con la naturaleza ya que la aseveración de los bajos rendimientos por parte de la mirada convencional está basado en un cultivo y no tiene en cuenta que los sistemas agroecológicos producen gran diversidad de productos y servicios ecosistémicos además de poder mantener la biodiversidad y la resiliencia de los ecosistemas.
Share