Viaje a PyCon Colombia 2018!

La Ida

Digamos que teníamos un itinerario ... subóptimo.

Salí de casa hacia Aeroparque el miércoles 7 a la 1PM para mi vuelo en LATAM de las 5PM a Sao Paulo. Arrancó bárbaro, llegué bien sin tráfico, pedí un café, hice el checkin en la máquina automática, me encontré con Andrew... todo sobre ruedas. El vuelo bien, teníamos pasillo y ventanilla sin nadie en el medio, viajamos cómodos y llegamos a Guarulhos a las 8:30PM.

Oh, Guarulhos. Nunca nada sale bien en Guarulhos. Sospecho que está construido sobre un cementerio indígena, si no no se explica.

Como nuestro siguiente vuelo salía recién a las 6:25AM y no teníamos ganas de pasar la noche sentados, habíamos hecho reservas en un hotel dentro del aeropuerto. Un hotel medio peculiar con habitaciones tipo camarote, camas cuchetas, pero económico. Total era dormir y tal vez darnos una ducha, nada más.

Bueno, primero seguimos los carteles de Hotel pero esos llevaban a un Tryp en terminal 3, que salía 250 dólares la noche y como no somos millonarios decidimos ir al que teníamos la reserva... que resulta que sí, está en el aeropuerto, pero del lado de afuera de migraciones en la terminal 2. Como teníamos hambre, cometimos un error y paramos a comer una hamburguesa en Bleriot.

El error no fue la hamburguesa, que estaba bastante buena, sino hasta que recorrimos todo el camino, salimos de migraciones y llegamos al hotel se hizo un poco tarde y nos cancelaron la reserva. Conocimos a un americano que lo charló a Andrew porque tenía una remera de los Patriots que acababan de perder el Super Bowl.

Así que, como es Guarulhos y nunca nada sale bien en Guarulhos, pasamos la noche en un par de starbucks tomando café.

A las 6:25AM tomamos el vuelo a Bogotá, el tramo mas largo que teníamos, unas 6 horas, pero como retrocedíamos 3 zonas llegamos a las 9AM. El vuelo ... bien. Dormí casi todo el viaje. Excepto que las azafatas eran culonas y me tocaban el hombro cada vez que pasaban.

Una vez en Bogotá, muertos de cansancio dijimos "tenemos 12 horas, no vamos a pasear un corno, busquemos un hotel". Teníamos reservas en uno llamado Cypress Normandia para la vuelta, tomamos un taxi a ese mismo por las dudas, y no había lugar. Nos dicen que hay un hotel llamado Connections ahí cerca y salimos con los bolsos. Caminamos tres cuadras, no lo encontramos, una señora muy amable en un café nos indica como llegar, llegamos.

El hotel es chiquito en frente de una plaza llamada "Las canchas" con chicos jugando a la pelota y un grupo de viejitos de un hogar al lado del hotel sentados en círculo jugando juegos.

El hotel tiene lugar. Lo que no tiene es agua. Y bueno, fuimos igual.

Me volví a comer algo al café donde la señora nos había ayudado, me comí un pastel de pollo con champiñones que era alucinante, torta de chocolate, un té helado y un café ... por 80 pesos argentinos. Sospecho que esta crónica va a tener un patrón donde me asombra lo baratas que son las cosas.

Volví al hotel, me desmayé, se hizo de tarde, volví al café a "almorzar" ... lasaña, agua, un bocadillo y un café.

Andrew se había ido al gimnasio, asi que me quedé solo, volvió el agua, pude usar el baño, nos juntamos de nuevo, vuelta a El Dorado para tomar el siguiente vuelo a las 9PM a medellín.

Como Andrew tiene un bolso lleno de merchandising, lo paran en seguridad por unos sospechosos llaveros-destapadores. Le terminamos regalando uno a cada una de las amorosas chicas de seguridad y pasamos.

Hablando de chicas de seguridad... en serio, re buena onda. Todo el mundo acá es amable. Pero eso es lo que pienso cuando viajo, no importa adonde viaje... no será que en comparación con el porteño promedio hasta los parisinos son amorosos? Sospecho que sí.

Vuelo a Medellín, llegamos sin inconveniente, es menos de una hora. Me hicieron despachar mi valija pero salió en el carousel en 2 minutos, cero problema.

El aeropuerto de Medellín queda medio lejos de la ciudad, así que tomamos un taxi. El camino sube a una montaña y después baja, todo por una ruta doble mano muy sinuosa. El taxista claramente estaba teniendo un mal dia e intentó suicidarse mientras nos llevaba, porque no sacó el pie del acelerador en todo el viaje. En exclusiva tengo un video del viaje:

El intento de suicidio fue fallido y llegamos al departamento que alquilamos por AirBnB, un lindo departamentito en un piso 15. No anduvo el wifi, asi que a la cucha.

Primer Dia de PyCon

Me desperté a las 6AM, miré por la ventana y ... wow.

https://lh3.googleusercontent.com/psn4PPuWK5vyA70CgHaZ6iWJnn8bkn6lCKVhge_30kxbiqgUiwk8gdjk_tJGegtSUDNfaODCF_fEvI2PmbtP33LMESYcRYggDQpgvwEmcCEkFcUz3PUgaoMKeQUY9A3E8xQg1fwmbl1nUIHJU44prL9TjK5Vz7xkd4copd1VUuIex1j2JamX7-bImd05Id16OcyyrsLCpmlnPBPHCn4jTOpMmlDK_aK6fKu76uWK6SvF2jVDyj8Fx6RiTR_pwG1Vc8hiInAb_Qu1gKw_RknakcQb-TtDm5qhbOHlRBiTTJhNq53O_wcovqVCtjoEXRoYfsXpHrS_Gu_-PBoSzuPCBD_Mj3y7SRbmSED8eaYqNEFfd8Dcn3eUNiIb92rM6hrk7HHvy-7y19m78KTh7-O8n6bm8gOcqs8GHbMxXeT69ImQ3Xr_NU8z10Xnew2gf3jVUI_KvEvTtL1MImgf4kr3DLXY5LbNaf7Vu40leDNN-L_n2_VQx13zwRwoZcobnBjlKb4f5wJQCz9oldWzu51y8s3CMpr1dH3t-bvQguIiWvHLUFzk_W70P6MO0Rq0mJRPOz_Z8Mp0IQqSTTmfzHvFa0GFDBGIDyVsVeLi2bih=w1920-h532-no

La vista desde el departamento.

Una ducha con agua fría (hay unas detalladas instrucciones para tener agua caliente que no funcionaron) y bajé a desayunar.

Ese desayuno, o sea huevos, arepa, queso y una chocolatada, sale $3000 colombianos, que son ... 22 pesos argentinos. Un dólar y alguito.

Volví a buscar a Andrew que se había quedado durmiendo, y salimos para Pycon.

La Pycon es en la universidad EAFIT que tiene el campus muy cerquita de donde estamos parando. Caminamos unas cuadras, pasamos un puente y llegamos. El lugar es muuuuuy lindo. Y hay ardillas.

La acreditación pasó sin problemas, el swag es copado (remera que hasta probablemente sea de mi talle y una botella de agua muy práctica), cero demora. Llegmos un poco tarde así que nos perdimos la primera plenaria y la bienvenida.

Un cafecito... chica amable me pregunta "oscurito?", le respondo "siempre", se puso colorada, y empiezo a sospechar que, ejem, tal vez haya sonado como que tenía una segunda intención. Pero no, señorita que me sirvió el café, le juro que solamente me gusta el café negro. Ahora que lo pienso... creo que me pasó lo mismo cuando dije que para mi remera "mientras mas X mejor, XXXL si tenés" ... ok, mil disculpas señorita de las remeras también.

Ah, mi acento les resulta sumamente gracioso. No hay problema, es mutuo :-)

Charla 1: Multi Tenant por @MiltonLn

Interesante! Descripción del problema, muestra algunas soluciones que son django-specific pero muy interesante igual.

Charla 2: Simulacion de sistema solar con Python

Primero: El que da la charla tiene como 12 años. No, mentira, debe tener más, pero me siento un anciano MAL. Creo entender que empezó 11° grado o sea tendrá 16?

La charla muy interesante, la astronomía es mi nerdeza fundacional (aguante el Centro de Observadores del Espacio de Santa Fe)

Muestra como va juntando piezas para terminar calculando órbitas y graficándolas. Es copado ver como alguien arranca aprendiendo algo y termina con una cosa que funciona, a veces uno se olvida esa sensación.

Charla 3: Pintando el Caos

Fractales! Linda charla introductoria, muy bien dada por Iris... un par de comentarios para la persona que "preguntó" último.

  1. Lo del cambio de condiciones iniciales y cambio en resultado ya lo había explicado ella bien cinco minutos antes. Te agradeció el mansplaining porque es demasiado educada.
  2. Eso no fue una pregunta.

Si vas a preguntar algo pero empezás con "primero un comentario" deberían apagarte el micrófono. Nota de color: en un momento la disertante dice que vio un documental y le llamó la atención porque era como esas cosas que uno ve "si se fuma un LSD" y alguien atrás mío comentó "como sabe?" ... hombre, creo que los efectos del LSD son de público conocimiento, y desde ya que la disertante no "sabe" porque el LSD no se fuma, se lame.

Charla 4: Modelado Computacional @nicoguaro

Queria ir a la de serverless pero ampliemos horizontes, hace mucho que no veo elementos finitos :-)

Una charla "mis ladrillos"! Mostrar como se puede construir una herramienta útil en base a un ecosistema preexistente agregando valor y encima con fines educativos. Súper claro, casi me da ganas de volver a aprender métodos numéricos. CASI.

Almuerzo y otras noticias parroquiales

Las charlas empiezan MUY temprano (8AM) y termina temprano (5PM) ... me gusta más que 10AM a 7PM? Tal vez. Pero ahora a almorzar.

Humitos y Johanna tienen un AirBnB en el mismo edificio que nosotros ... eso es una coincidencia.

En fin, me salteé el almuerzo gratis y me fui a comer una hamburguesa introvertida para recargar baterías.

Charla 5: Python memory management

  • Tiene un slide sobre el viejo favorito "256 is 256"
  • Plot twist! "foo" is "foo" pero "foo!" no es "foo!" (extra: sys.intern)
  • Sorpresa!

Charla copada, no sabía algunas de estas cosas, a pesar de haber hecho experimentos en manejo de memoria hace un tiempo.

Tejo! Petardos! Moco de Gorila!

Me fui al depto porque estaba medio cansado y por el camino pasé por un mercado a comprar algo para la cena. Cosas que no compré:

Cosas que si compre:

La vista del balcón del depto había tenido una evolución a lo Pokémon:

Y ya estaba tranquilito en la cama viendo Netflix cuando me llega un mensaje de Humitos para que me junte con organizadores y keynotes en una salida. Me da una dirección: Carrera 48 #46 sur 150.

Expliqué las direcciones en Colombia? Carreras van para un lado, las calles cruzan, las calles son sur o norte, y te dan siempre la carrera, la calle, el lado y el número. El problema es que google maps no entiende esas direcciones, por lo menos no en el formato que te las dan, así que hay que adivinar un poco.

En este caso dije "tranquilo, me tomo un taxi". Casi ninguna historia en Medellín que empieza con "me tomo un taxi" es tranquila. Me tomo el taxi, y el conductor me dice "y donde es eso?" le respondo "si no sabe usted que maneja un taxi..." "Es que la ciudad es grande y hay lugares que no voy".

Bueno, es en Envigado. Lo guío yo con mi aproximación a la dirección, y me dice "aquí no puede ser" "no importa, dejemé, yo lo encuentro" y ... me dice que no se animaba a dejarme porque no quería tenerme en su conciencia (!?) Sinceramente, creo que hacer enojar a Pablo Escobar debía ser menos peligroso que andar en taxi en Medellín, porque los taxistas son dementes.

Me bajo, pregunto, me llega un mensaje de Javier Mansilla (de paso, tenía 4% de batería porque vivo peligrosamente) y resulta que el evento es "adentro del polideportivo, al fondo, doblando en la piscina, pasando la cancha de futbol de tierra".

Es una cancha de tejo.

El tejo en Colombia es distinto. Elegís una pesa de plomo con forma de cono truncado, te parás a cierta distancia de un cajón inclinado lleno de arcilla con dos triángulos rosa y revoleás la pesa tratando de acercarte a los triángulos.

Y si le pegás a un triángulo... explota. LOS COLOMBIANOS INVENTARON MI DEPORTE FAVORITO

Así que nos pasamos dos horas tratando de hacer que exploten cosas mientras tomábamos una Pilsen y alguna "colombiana" que es una gaseosa local "sabor cola". No sé cola de qué animal sería, pero ... duelen los dientes del azúcar que tiene.

La cena fue una picada de:

  • Chicharrones (grasa de cerdo frita crocante)
  • Plátano frito crocante
  • Salchicha
  • Arepa
  • Papa
  • Morcilla rellena con arroz
  • Una salsita "picante" (no era picante)

Que tal? Todo muy bien. La morcilla con arroz es mas fácil de comer que la versión mongol del mismo plato en que uno tiene que sopar la sangre con la torta de arroz y cocinarla en sopa. Pero livianito no era eso.

Terminamos la sesión deportiva, volvimos en Uber con Javier y Humitos, llego al depto y ... Andrew no estaba, así que me fuí al depto de los muchachos a esperar. Humitos me dio remeras y stickers para llevar a regalar a Argentina, Andrew volvió, me fui a dormir.

Dia 2 de Pycon Colombia

Me desperté tarde, desayuné arepa con huevo y café, propuse una lightning talk.

Charla 1: Serverless for Pythonistas de @jonatasbaldin

No puedo sacarme de encima la idea de que serverless es fancy cgi, pero de todas formas quiero probar hacer algo con esto.

Charla 2: Architecture for machine learning apps de @jorlugaqui

Arrancó con una explicación de como pasar de un notebook provisto por data scientists a parte de una app django, pero la segunda mitad fue mas anécdotas y quejas de la interacción con data scientists. He hecho cosas parecidas en charlas y ... no debería haberlo hecho yo tampoco.

Aparte, hizo que la sesión de Q&A fuera: "Hola, yo soy data scientist. Eso que dijiste de nosotros ...". Que me está pasando? Estoy hecho un pacifista de mierda.

Intervalo

Me perdí la charla de bytecode de Rocky Bernstein porque reescribí los slides para la charla relámpago que propuse.

Charla 3: Django Girls con @ellaquimica

Excelente charla, Johanna vibraba a 300Hz de lo nerviosa pero salió muy bien. Muy buena sección de Q&A.

Charla 4: La PSF con @reydelhumo

Excelente, no mas para decir :-)

Charla Relampago!

La di. Hablé rápido aún para mis standards, pero creo que se entendió, y se va a entender mejor si la suben a youtube y la ven con velocidad 0.5x. Creo que salió bastante mejor que la charla con el mismo tema en la PyCon Argntina de 2009.

Charla 5: Naomi Ceder, Antipatterns para diversidad

Muy interesante, una charla que se ve que Naomi la da desde el corazón y completamente contra su voluntad porque es necesaria.

Cena: Hatoviejo!

Me invitaron (inmerecidamente) a la cena de speakers en un restaurante típico colombiano llamado Hatoviejo ... comí una cazuela típica, muuuy rica.

Al salir fui al baño y había una impresión de un Botero... firmada y dedicada por Botero! En el baño!

Mucha charla con vecinos de mesa, después fuimos a tomar unas cervezas a el poblado (la zona de joda nocturna de Medellín) tomé una London Pride, charla diversión y a la cama.

Dia 3 de Pycon Colombia

Me desperté sintiéndome muy mal, así que me perdí los workshops de la mañana, y llegué para las keynotes de la tarde.

Charla 1: Deborah Hanus

Consideraciones éticas sobre Machine Learning? Super interesante!!!! Une mi interés en detalles técnicos de implementación de cosas con mi amor por discutir cosas abstractas.

Charla 2: Audrey Roy Greenfeld y Daniel Roy Greenfeld

Ya había visto la misma charla en Argentina hace un tiempo. Son adorables, pero es una charla super light.

Charla 3: John Roa, termina Pycon Colombia!

Despedidas, fotos, etc.

Post-Pycon

Me seguía sintiendo mal, me fui al departamento.

Dia 1 Post-Pycon

Teníamos vuelo a la noche a Bogotá, pero seguía medio descompuesto, no hice turismo, comí tranqui, hice las valijas y me fui a un shopping, el Santa Fe ... me compré calzoncillos, almorcé un QBano y a prepararme para la vuelta.

Vuelo de regreso a Bogotá

Tomamos un Uber al aeropuerto, y fue una experiencia MUCHO mas tranquila que el taxi unos dias antes. Llegamos, la maquina de checkin se colgó imprimiendo el boarding pass, por lo que fuimos a la ventanilla. No nos imaginábamos que eso sería el comienzo de la anécdota más complicada del viaje.

Vamos al mostrador, como teniamos asientos separados y se había colgado todo nos dice "les voy a dar los dos asientos pasillo en la fila de salida, tienen lugar extra y viajan juntos". Genial! Esos asientos estaban 25 dólares extra en el checkin online!

Vamos tipo "je, somos re grosos, tenemos asientos mejores", subimos y vemos algo raro.

Andrew tenía el asiento pasillo del lado izquierdo mirando hacia la cola del avión. En el asiento del medio no había nadie, en el de la ventanilla había un hombre ... peleándose con un tipo de la aerolínea. Le decía cosas como "solo te pedí un favor y no eres capaz de hacerlo" y el comisario de a bordo lo ignoraba o le decía "no es mi trabajo".

Resulta que cuando subió este muchacho tiró el bolso en el pasillo y le dijo al comisario "subímelo al portaequipaje" a lo que el hombre obviamente le dijo "no" y ya quedó de mal humor.

Se sienta Andrew, yo me siento del otro lado del pasillo al lado de una chica.

Despega el avión. MUCHA turbulencia. Es un viaje corto pero es todo arriba de montañas. El avión se movía con ganas.

La chica al lado mío se empieza a descomponer, todo el mundo medio nervioso.

El quía de al lado de Andrew tenía, sospechosamente, dos botellas de agua. Una grande y una pequeña. Tomaba un trago de la grande, un trago de la chica. Resulta que la botella grande tenía aguardiente.

Apenas despegamos, se sacó el cinturón, y cuando ya estábamos medio nerviosos le empieza a dar charla a Andrew. Resulta que Andrew odia volar. Se pone nervioso. Y el coso dandole charla.

"Argentino? Boca o River?"

"San Lorenzo"

"Ahhh el nuevo gasómetro!"

Hasta ahi todo bien, pero Andrew le empieza a dar menos pelota.

El tipo se empieza a enojar.

Viene la azafata a pedirle que se calme. El tipo la toca, le dice que es linda...

Viene el comisario de a bordo a pedirle que deje de hinchar las pelotas. El tipo le dice que el no tiene problemas, el problema es el argentino agrandado este, que el solo queria charlar.

Andrés trata de leer, le dice que deje de hablarle, que el está nervioso y que no tiene ganas de hablar.

"Ah, estos argentinos que se creen dios ... " y sigue hablando pavadas. Ya la botella de aguardiente tenía aproximadamente un litro menos.

Viene el comisario de a bordo, le ofrece a Andrew irse adelante a otro asiento. "Si por favor" y se va.

El zopenco ahora me empieza a hablar a mí. "Ay, que se ofenden los argentinos" "Que son muy agrandados" "Que acá estamos en Colombia y solo traté de ser amistoso porque somos gente amistosa" "Que los argentinos se creen dios".

Yo le respondo que todo bien con los colombianos, que me llevo bárbaro con todos los que conocí en esta semana, pero que no tengo ganas de charlar con un borracho que me insulta por mi nacionalidad.

Otros pasajeros me dicen que no me caliente. Les digo que no va a ser un borracho idiota el que me caliente.

Aterrizamos.

Empieza el papanatas a llamar por teléfono "Oye [nombre], puedes venir al dorado que tengo un problema con unos argentinos" Me empieza a decir "ya nos vamos a ver afuera en el aeropuerto, estás en Colombia y aquí somos todos iguales, no porque seas argentino vas a tener coronita".

Le respondo "me estás diciendo que me vas a pelear? En un aeropuerto? Y me lo estás diciendo en un avión que todavía no desembarcó?"

El avión carretea, llega a la puerta pero no se abren.

Mensaje del capitán "quedense sentados que tenemos que resolver una situación".

El zoquete me sigue amenazando, yo me río en su cara.

Viene el comisario de a bordo y lo lleva adelante, se queda parado en el pasillo.

Los vecinos de asiento me piden disculpas en nombre de Colombia, yo les digo "es el primer colombiano idiota que conozco en una semana, en Buenos Aires esa frecuencia sería un milagro"

El papafrita, desde la parte delantera del avión, sigue llamando amigos para que vengan a fajarnos, mientras me amenaza a los gritos.

Llega la policía, se lo lleva, nunca más lo vimos.

Moraleja: no amenaces gente a los gritos en un avión. No tomes un litro de aguardiente en vuelo.

Llegados a Bogotá, vamos al hotel Cypress Normandia, tenemos la habitación, pedimos delivery de dos hamburguesas horribles y nos dormimos. Al día siguiente: turismo

Dia 2 post-PyCon

Nos levantamos temprano, me fui a desayunar con mi amiga personal la señora del Cafe del Monte desayuno, vuelvo y salimos con Andrew.

Tomamos un taxi a la parte histórica de la ciudad. Pasamos por una "zona de tolerancia" por un mercado de vegetales, y llegamos.

Vamos a la Plaza Bolívar, vemos iglesias, tomamos café, estaban filmando un documental!

Voy a un supermercado y compro condimentos y café, y salimos para Monserrate.

Vamos caminando unas 30 cuadras, escupiendo los pulmones. Bogotá está ALTA. Llegamos a la base del monte, y no podemos tomar el cablecarril porque solo funciona de mañana. Tomamos el funicular, un trencito que va por una vía prácticamente vertical, y llegamos arriba.

La vista es espectacular, vemos la iglesia, paseamos, sacamos fotos, compramos souvenirs, y bajamos.

Volvemos al hotel, vamos al aeropuerto y salimos. El resto del viaje no tiene mucho interés, llegamos a Aeroparque, nos despedimos, y colorín colorado, esta crónica de viaje se ha terminado.

Más fotos del viaje en este album de Google Photos.

An Innocent Client (Joe Dillard, #1)

  • Author: Scott Pratt
  • Rating:
  • See in goodreads
  • Review:

    For a change of pace, I read this. I had not read legal fiction for a long time!

    It's ok, fun, not badly written, even if the main character is:

    * A special forces veteran
    * A child abuse survivor
    * The best lawyer in town
    * In the process of retiring to become a teacher
    * Married to a gorgeous dancer
    * Gorgeous
    * Parent of a dancer
    * Parent of a MLB prospect kid
    * Working off his 10-acre property overlooking a lake
    * Only working death penalty cases
    * Morally conflicted

    Because really, there is such a thing as too much backstory. On the other hand, the plot is kinda thin.

    So, fun short read.

    Addition:

    * His mother is dying
    * His sister is a drug addict who has stolen from him

    I am sure I am forgetting something else.

GitHub and GitLab for newbies

I wrote a git tutorial for those who don't know git where I tried to explain how to use Git for version control on your local machine.

Of course those of you who know about these things already know that half the fun of git is not using it locally, but using a server that can centralize the develpment and allow collaboration.

Well, good news! I just wrote the chapter where I cover that part!

Read and let me know what you think:

Git Hosting

Playing With Picolisp (Part 1)

I want to learn new languages. But new as in "new to me", not new as in "created last week". So I decided to play with the grandaddy of all cool languages, LISP. Created in 1958, it's even older than I, which is good because it's experienced.

One "problem" with LISP is that there are a million LISPs. You can use Scheme or Common Lisp, or Emacs' Lisp, or a bazillion others. I wanted something simple so it was supposed to be Scheme... but a few days ago I ran into something called Picolisp and it sounded so cool.

Read more…

Playing with Nim

A few days ago I saw a mention in twitter about a language called Nim

And... why not. I am a bit stale in my programming language variety. I used to be fluent in a dozen, now I do 80% python 10% go, some JS and almost nothing else. Because I learn by doing, I decided to do something. Because I did not want a problem I did not know how to solve to get in the way of the language, I decided to reimplement the example for the python book I am writing: a text layout engine that outputs SVG, based on harfbuzz, freetype2 and other things.

This is a good learning project for me, because a lot of my coding is glueing things together, I hardly ever do things from scratch.

So, I decided to start in somewhat random order.

Preparation

I read the Nim Tutorial quickly. I ended referring to it and to Nim by example a lot. While trying out a new language one is bound to forget syntax. It happens.

Wrote a few "hello world" 5 line programs to see that the ecosystem was installed correctly. Impression: builds are fast-ish. THey can get actually fast if you start using tcc instead of gcc.

SVG Output

I looked for libraries that were the equivalent of svgwrite, which I am using on the python side. Sadly, such a thing doesn't seem to exist for nim. So, I wrote my own. It's very rudimentary, and surely the nim code is garbage for experienced nim coders, but I ended using the xmltree module of nim's standard library and everything!

import xmltree
import strtabs
import strformat

type
        Drawing* = tuple[fname: string, document: XmlNode]

proc NewDrawing*(fname: string, height:string="100", width:string="100"): Drawing =
        result = (
            fname: fname,
            document: <>svg()
        )
        var attrs = newStringTable()
        attrs["baseProfile"] = "full"
        attrs["version"] = "1.1"
        attrs["xmlns"] = "http://www.w3.org/2000/svg"
        attrs["xmlns:ev"] = "http://www.w3.org/2001/xml-events"
        attrs["xmlns:xlink"] = "http://www.w3.org/1999/xlink"
        attrs["height"] = height
        attrs["width"] = width
        result.document.attrs = attrs

proc Add*(d: Drawing, node: XmlNode): void =
        d.document.add(node)

proc Rect*(x: string, y: string, width: string, height: string, fill: string="blue"): XmlNode =
        result = <>rect(
            x=x,
            y=y,
            width=width,
            height=height,
            fill=fill
        )

proc Text*(text: string, x: string, y: string, font_size: string, font_family: string="Arial"): XmlNode =
        result = <>text(newText(text))
        var attrs = newStringTable()
        attrs["x"] = x
        attrs["y"] = y
        attrs["font-size"] = font_size
        attrs["font-family"] = font_family
        result.attrs = attrs

proc Save*(d:Drawing): void =
   writeFile(d.fname,xmlHeader & $(d.document))

when isMainModule:
        var d = NewDrawing("foo.svg", width=fmt"{width}cm", height=fmt"{height}cm")
        d.Add(Rect("10cm","10cm","15cm","15cm","white"))
        d.Add(Text("HOLA","12cm","12cm","2cm"))
        d.Save()

While writing this I ran into a few issues abd saw a few nice things:

To build a svg tag, you can use <>svg(attr=value) which is delightful syntax. But what happens if the attr is "xmlns:ev"? That is not a valid identifier, so it doesn't work. So I worked around it by creating a StringTable filling it and setting all attributes at once.

A good thing is the when keyword. usingit as when isMainModule means that code is built and executed when svgwrite.nim is built standalone, and not when used as a module.

Another good thing is the syntax sugar for what in python we would call "object's methods".

Because Add takes a Drawing as first argument, you can just call d.Add() if d is a Drawing. Is simple, it's clear and it's useful and I like it.

One bad thing is that sometimes importing a module will cause weird errors that are hard to guess. For example, this simplified version fails to build:

import xmltree

type
        Drawing* = tuple[fname: string, document: XmlNode]

proc NewDrawing*(fname: string, height:string="100", width:string="100"): Drawing =
        result = (
            fname: fname,
            document: <>svg(width=width, height=height)
        )

when isMainModule:
        var d = NewDrawing("foo.svg")
$ nim c  svg1.nim
Hint: used config file '/etc/nim.cfg' [Conf]
Hint: system [Processing]
Hint: svg1 [Processing]
Hint: xmltree [Processing]
Hint: macros [Processing]
Hint: strtabs [Processing]
Hint: hashes [Processing]
Hint: strutils [Processing]
Hint: parseutils [Processing]
Hint: math [Processing]
Hint: algorithm [Processing]
Hint: os [Processing]
Hint: times [Processing]
Hint: posix [Processing]
Hint: ospaths [Processing]
svg1.nim(9, 19) template/generic instantiation from here
lib/nim/core/macros.nim(556, 26) Error: undeclared identifier: 'newStringTable'

WAT? I am not using newStringTable anywhere! The solution is to add import strtabs which defines it, but there is really no way to guess which imports will trigger this sort of issue. If it's possible that importing a random module will trigger some weird failure with something that is not part of the stdlib and I need to figure it out... it can hurt.

In any case: it worked! My first working, useful nim code!

Doing a script with options / parameters

In my python version I was using docopt and this was smooth: there is a nim version of docopt and using it was as easy as:

  1. nimble install docopt
  2. import docopt in the script

The usage is remarkably similar to python:

import docopt
when isMainModule:
        let doc = """Usage:
        boxes <input> <output> [--page-size=<WxH>] [--separation=<sep>]
        boxes --version"""

        let arguments = docopt(doc, version="Boxes 0.13")
        var (w,h) = (30f, 50f)
        if arguments["--page-size"]:
            let sizes = ($arguments["--page-size"]).split("x")
            w = parse_float(sizes[0])
            h = parse_float(sizes[1])

        var separation = 0.05
        if arguments["--separation"]:
            separation = parse_float($arguments["--separation"])
        var input = $arguments["<input>"]
        var output = $arguments["<output>"]

Not much to say, other that the code for parsing --page-size is slightly less graceful than I would like because I can't figure out how to split the string and convert to float at once.

So, at that point I sort of have the skeleton of the program done. The missing pieces are calling harfbuzz and freetype2 to figure out text sizes and so on.

Interfacing with C libs

One of the main selling points of Nim is that it interfaces with C and C++ in a striaghtforward manner. So, since nobody had wrapped harfbuzz until now, I could try to do it myself!

First I tried to get c2nim working, since it's the recommended way to do it. Sadly, the version of nim that ships in Arch is not able to build c2nim via nimble, and I ended having to manually build nim-git and c2nim-git ... which took quite a while to get right.

And then c2nim just failed.

So then I tried to do it manually. It started well!

  • To link libraries you just use pragmas: {.link: "/usr/lib/libharfbuzz.so".}

  • To declare types which are equivalent to void * just use distinct pointer

  • To declare a function just do some gymanstics:

    proc create*(): Buffer {.header: "harfbuzz/hb.h", importc: "hb_buffer_$1" .}

  • Creates a nim function called create (the * means it's "exported")

  • It is a wrapper around hb_buffer_create (see the syntax there? That is nice!)

  • Says it's declared in C in "harfbuzz/hb.h"

  • It returns a Buffer which is declared thus:

type
    Buffer* = distinct pointer

Here is all I could do trying to wrap what I needed:

{.link: "/usr/lib/libharfbuzz.so".}
{.pragma: ftimport, cdecl, importc, dynlib: "/usr/lib/libfreetype.so.6".}

type
        Buffer* = distinct pointer
        Face* = distinct pointer
        Font* = distinct pointer

        FT_Library*   = distinct pointer
        FT_Face*   = distinct pointer
        FT_Error* = cint

proc create*(): Buffer {.header: "harfbuzz/hb.h", importc: "hb_buffer_$1" .}
proc add_utf8*(buffer: Buffer, text: cstring, textLength:int, item_offset:int, itemLength:int) {.importc: "hb_buffer_$1", nodecl.}
proc guess_segment_properties*( buffer: Buffer): void {.header: "harfbuzz/hb.h", importc: "hb_buffer_$1" .}
proc create_referenced(face: FT_Face): Font {.header: "harfbuzz/hb.h", importc: "hb_ft_font_$1" .}
proc shape(font: Font, buf: Buffer, features: pointer, num_features: int): void {.header: "harfbuzz/hb.h", importc: "hb_$1" .}

proc FT_Init_FreeType*(library: var FT_Library): FT_Error {.ft_import.}
proc FT_Done_FreeType*(library: FT_Library): FT_Error {.ft_import.}
proc FT_New_Face*(library: FT_Library, path: cstring, face_index: clong, face: var FT_Face): FT_Error {.ft_import.}
proc FT_Set_Char_Size(face: FT_Face, width: float, height: float, h_res: int, v_res: int): FT_Error {.ft_import.}

var buf: Buffer = create()
buf.add_utf8("Hello", -1, 0, -1)
buf.guess_segment_properties()

var library: FT_Library
assert(0 == FT_Init_FreeType(library))
var face: FT_Face
assert(0 == FT_New_Face(library,"/usr/share/fonts/ttf-linux-libertine/LinLibertine_R.otf", 0, face))
assert(0 == face.FT_Set_Char_Size(1, 1, 64, 64))
var font = face.create_referenced()
font.shape(buf, nil, 0)

Sadly, this segfaults and I have no idea how to debug it. It's probably close to right? Maybe some nim coder can figure it out and help me?

In any case, conclusion time!

Conclusions

  • I like the language
  • I like the syntax
  • nimble, the package manager is cool
  • Is there an equivalent of virtualenvs? Is it necessary?
  • The C wrapping is, indeed, easy. When it works.
  • The availability of 3rd party code is of course not as large as with other languages
  • The compiling / building is cool
  • There are some strange bugs, which is to be expected
  • Tooling is ok. VSCode has a working extension for it. I miss an opinionated formatter.
  • It produces fast code.
  • It builds fast.

I will keep it in mind if I need to write fast code with limited dependencies on external libraries.

Código Charla PyDay "Como Hacer una API REST en Python, spec first"

El 4/4/2018 di una charla en un PyDay sobre como implementar una API REST a partir de una especificación hecha en Swagger/OpenAPI usando Connexion

/images/pyday-api-rest.jpg

Foto tomada por Yamila Cuestas

Si bien no pude grabar la charla (alguien en la audiencia si lo hizo, pero no me dio el video! Pasame el video, persona de la audiencia!) y no hay slides, acá está el código que mostré, que es relativamente sencillo y fácil de seguir.

Código de la charla

Cualquier cosa pregunten.

PD: Sí, podría hacer la charla en un video nuevo. Sí, me da mucha pereza.

My Git tutorial for people who don't know Git

As part of a book project aimed at almost-beginning programmers I have written what may as well pass as the first part of a Git tutorial. It's totally standalone, so it may be interesting outside the context of the book.

It's aimed at people who, of course, don't know Git and could use it as a local version control system. In the next chapter (being written) I cover things like remotes and push/pull.

So, if you want to read it: Git tutorial for people who don't know git (part I)

PS: If the diagrams are all black and white, reload the page. Yes, it's a JS issue. Yes, I know how to fix it.