How I Learned to Stop Worrying and Love JSON Schema


This post operates on a few shared assumptions. So, we need to explicitly state them, or otherwise you will read things that are more or less rational but they will appear to be garbage.

  • APIs are good
  • Many APIs are web APIs
  • Many web APIs consume and produce JSON
  • JSON is good
  • JSON is better if you know what will be in it

So, JSON Schema is a way to increase the number of times in your life that JSON is better in that way, therefore making you happier.

So, let's do a quick intro on JSON Schema. You can always read a much longer and surely better one from which I stole most examples at Understanding JSON Schema. later (or right now, it's your time, lady, I am not the boss of you).


So, a JSON Schema describes your data. Here is the simplest schema, that matches anything:

{ }

Scary, uh? Here's a more restrictive one:

  "type": "string"

That means "a thing, which is a string." So this is valid: "foo" and this isn't 42 Usually, on APIs you exchange JSON objects (dictionaries for you pythonistas), so this is more like you will see in real life:

  "type": "object",
  "properties": {
    "street_address": { "type": "string" },
    "city": { "type": "string" },
    "state": { "type": "string" }
  "required": ["street_address", "city", "state"]

That means "it's an object", that has inside it "street_address", "city" and "state", and they are all required.

Let's suppose that's all we need to know about schemas. Again, before you actually use them in anger you need to go and read Understanding JSON Schema. for now just assume there is a thing called a JSON Schema, and that it can be used to define what your data is supposed to look like, and that it's defined something like we saw here, in JSON. Cool?

Using schemas

Of course schemas are useless if you don't use them. You will use them as part of the "contract" your API promises to fulfill. So, now you need to validate things against it. For that, in python, we can use jsonschema

It's pretty simple! Here is a "full" example.

import jsonschema

schema = {
  "type": "object",
  "properties": {
    "street_address": {"type": "string"},
    "city": {"type": "string"},
    "state": {"type": "string"},
  "required": ["street_address", "city", "state"]

    "street_address": "foo",
    "city": "bar",
    "state": "foobar"
}, schema)

If the data doesn't validate, jsonchema will raise an exception, like this:

>>> jsonschema.validate({
...     "street_address": "foo",
...     "city": "bar",
... }, schema)
Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
  File "jsonschema/", line 541, in validate
    cls(schema, *args, **kwargs).validate(instance)
  File "jsonschema/", line 130, in validate
    raise error
jsonschema.exceptions.ValidationError: 'state' is a required property

Failed validating 'required' in schema:
    {'properties': {'city': {'type': 'string'},
                    'state': {'type': 'string'},
                    'street_address': {'type': 'string'}},
     'required': ['street_address', 'city', 'state'],
     'type': 'object'}

On instance:
    {'city': 'bar', 'street_address': 'foo'}

Hey, that is a pretty nice description of what is wrong with that data. That is how you use a JSON schema. Now, where would you use it?

Getting value out of schemas

Schemas are useless if not used. They are worthless if you don't get value out of using them.

These are some ways they add value to your code:

  • You can use them in your web app endpoint, to validate things.
  • You can use them in your client code, to validate you are not sending garbage.
  • You can use a fuzzer to feed data that is technically valid to your endpoint, and make sure things don't explode in interesting ways.

But here is the most value you can extract of JSON schemas:

You can discuss the contract between components in unambiguous terms and enforce the contract once it's in place.

We are devs. We discuss via branches, and comments in code review. JSON Schema turns a vague argument about documentation into a fact-based discussion of data. And we are much, much better at doing the latter than we are at doing the former. Discuss the contracts.

Since the document describing (this part of) the contract is actually used as part of the API definitions in the code, that means the document can never be left behind. Every change in the code that changes the contract is obvious and requires an explicit renegotiation. You can't break API by accident, and you can't break API and hope nobody will notice. Enforce the contracts.

Finally, you can version the contract. Use that along with API versioning and voilá, you know how to manage change! Version your contracts.

  • Discuss your contracts
  • Enforce your contracts
  • Version your contracts

So now you can stop worrying and love JSON Schema as well.

Creating Languages For Dummies


I don't have the usual programmer's education. I studied maths, and then dropped out of that, and am mostly self-taught. So, there are some parts of programming I always saw wearily, thinking to myself that I really should go to school to learn them. One remarkable such area is parsing and implementing languages.

Well... sure, school is always a good idea, but this is not that hard. In this article I will explain how to go from nothing to a functioning, extensible language, using Python and PyParsing. If you are as scared of grammars, parsers and all that jazz as I used to be, come along, it's pretty simple,

Read more…

So, Things Happened.

Turns out I got my computer stolen in November 8th, 2015, and that meant I had to restore this site from backup, which was also stolen. So, oops?

However, it turns out that if you wait a year and a half and then spend a few hours munging bits from the published site into a 3-years-older backup, it's possible to "decompile" a Nikola-based site back into a working site. Or at least a site with the same number of posts as the "old" site had. Which is something, right?

Still need to check for dead links, and I lost the "originals" of a bunch of images from trips, but nothing terrible.

Will I write again? Who knows. But at least if I don't it's because I don't want to.

Brute Force Works

Last night, Juanjo Conti tweeted this:

Or, in english: "Using exactly once the digits 1,3,4 and 6, and any of the four basic operations, obtain 24."

I first spent a couple of minutes thinking about it and then it hit me: there is no point in thinking this sort of problem, because:

  1. Brute forcing it will take less time
  2. What you do while "thinking" it is sort of lame, isn't it?

So, here is a more-or-less general solution for any of these problems.

from __future__ import print_function, division
import itertools

numbers = ['1','3','4','6']
target = 24

# Having '' as an operation allows for solution (14-6)*3, which
# may or may not be valid depending on rule interpretation.
operations =  ['*','/','+','-','']


for nums in itertools.permutations(numbers):
    for ops1 in itertools.combinations_with_replacement(operations, 3):
        for ops2 in itertools.permutations(ops1):
            for t in (t1, t2):
                s = t.format(*(nums+ops2))
                    if eval(s) == target:
                except (ZeroDivisionError, SyntaxError, TypeError):

Of course you can make it solve any problem of this class by adjusting numbers and target. There is also a possible extra solution if eval(s) == -target where you just need to add a unary - to the expression, but who cares.

Did I miss something? Is this really a general solution?

De San Isidro a Malta y de vuelta.

NOTA Esta es la crónica de un viaje que hice en 2014, y tenía escrita por la mitad. Ya bastante poco escribo como para encima no publicar algo que escribí! Así que acá va. Termina abruptamente, como todo.

Antes que nada: si quieren ver fotos, están acá si ven solo 3, aguanten que tengo que arreglar el plugin de galerias (yupiiii)

Estoy sentado en el aeropuerto de Palermo, comiendo un canoli y tomando un cafecito, y no voy a dejar que este viaje se me escape de la memoria como otros. Porque nunca escribí los últimos días en Londres con Rosario, ni la escapada a Yosemite con Lucio y Chipaca, y ser vago no está bueno. Y porque tengo 5 horas hasta que salga el avión y me embolo.

Entonces... la empresa me mandó a trabajar a Malta unos días, y como pasa casi siempre, hay un día de más al principio, un día de más al final, y los pasajes son más baratos si uno llega el sábado y se va el domingo, así que... que hay cerca de Malta que uno pueda querer visitar? Bueno, un montón de cosas, pero la familia de mi vieja es italiana, y yo nunca puse ni un pie en Italia hasta la semana pasada. Claro, es la otra punta de italia, ellos vivían en la caña de la bota, más o menos adonde estaría el cierre, y Malta queda cerca de la pelota que dicha bota está pateando, Sicilia.

Así que con mi fiel valijita encaré para Italia, Ezeiza->Roma->Palermo->????->Malta y vuelta.

El día del viaje era justo el 23 de mayo, que es el día que la escuela de Tato tenía acto, y Tato hacía de caballero colonial, así que a las 6:30 AM estaba haciendo hebillas para zapato con cartones y papel de aluminio, pero llegó todo a tiempo, y estaba super caballeroso colonialoso el mocoso.

Pero claro, el acto terminó tipo 9:30 y yo no tenía ni hecha la valija, así que corrí... ok, troté... ok, caminé tranqui a casa, hice la valija y salí para Ezeiza con tiempo, más o menos para llegar 2:30 antes, como siempre.

Llego y la gente de la AFIP había decidido que "la letra con sangre entra" (sic). Hace meses que uno puede declarar los aparatos que saca del país via internet. Pero nadie lo hacía, entonces en la ventanilla se negaban a atender a los que no lo tenían hecho. Para que no los lincharan, pusieron un kiosquito de internet (2 compus) y una señora ayudando a hacerlo ahi mismo. Hacías una horita de cola en el kiosco, llenabas el formulario, trotabas a la ventanilla, hacías media horita de cola, firmabas el formulario, y listo!

Pero claro... si tenés 2 horas para llegar al avión, medio que quedás jugado... por suerte me di cuenta que era una vulgar pagina web, y que el aeropuerto tiene wifi gratis, así que la hice en el celu (después de hacer 45 minutos de cola), fui a hacer la otra media hora, y listo!

Aunque... bueno, resulta que Alitalia no sale de ahí. Sale de la terminal C. Y yo estaba en la A. Y el checkin cierra una hora antes del vuelo. Entonces me quedaban 6 minutos para cruzar Ezeiza. NO PROBLEM, llegué con los bofes en la mano, la chica de Alitalia amablemente me recibió la valija, aunque llegué tres minutos tarde, obviamente no había cola en migraciones, y llegué cuando la gente ya estaba abordando.

El vuelo ... tenía un asiento sin nadie adelante en la segunda fila. La 1ra tenia dos asientos, la 3ra tres, y yo estaba en el pasillo. LUGAR pa' las patas! Aunque... al lado mío viajaban dos viejitos. El viejito masculino me dice "a mi me dijeron que este asiento daba al pasillo, porque tengo un problema y tengo que ir al baño cada 30 minutos" y la viejita femenina de la ventanilla llama a la azafata porque su asiento no se reclina.'Así que saqué el caballero interior, me agarré el asiento de la ventanilla, la señora viejita tuvo un asiento que reclina, el señor viejito un asiento en el pasillo (que salía $500 extra, pero no se los cobré), y yo me quedé acovachado en la ventanilla. Lo bueno: la comida no estuvo mal, y las rodillas no tocaban el asiento de adelante, así que todo bien.

Me vi "We are the Millers" y otra que no me acuerdo, me leí más o menos la mitad del 2do libro de Kingkiller Chronicle, y llegamos a Roma. De ahí super tranqui (porque tenía 4 horas para la combinación), me fuí a un bar y me tomé mi primer café en Italia, y me comí mi primera porción de torta. En un estado de éxtasis alimentario, y pensando que este viaje pintaba bien hice tiempo, tomé el vuelo cortito a Palermo, y ahí me esperaba mi ladero automotriz (porque le gusta manejar) Lucio.

El asiento en el vuelo a Palermo estaba bueno...

Ofendidísimo porque no tenía el cartelito "Mr Alsina" de rigor nos fuimos a buscar el fiat 500 alquilado, y después de media hora averiguando como salir del parking... bueno, salimos del parking. Y nos fuimos a Palermo.

Palermo está hecho bolsa. Es una ciudad que evidentemente en alguna época fué mucho más rica que ahora, porque está llena de edificios antiguos y hermosos venidos abajo, y todo está sucio. Paseamos, sacamos fotos, comimos (pizza! En Italia! YEAH) tomamos, caminamos, etc. Y se nos acabaron las ideas.

Resulta que otros argentinos (Chipaca y Ra) estaban haciendo algo parecido pero en la otra punta de Sicilia, entonces dijimos... vamos? Cuanto se puede tardar en llegar? Bueno, mucho, pero igual nos metimos en la autopista con destino Siracusa. Por el camino, vimos unas 645968 casitas en la cima de una colina, abandonada y hecha bolsa. Millones y millones de naranjos. Cientos de miles de otros arbolitos (olivos?), todos los fiats del universo.

Para llegar a Siracusa hay que pasar por Catania y cruzar casi toda Sicilia. Cuando ya llevábamos unas 4 horas en la autopista dijimos "vayamos a un pueblito" lo que se convirtió en "agarremos la próxima salida", lo que nos llevó a Caltanissetta, tal vez la ciudad menos turística de Sicilia, nos subimos a un estacionamiento en el techo de un negocio de algún ramo misterioso, sacamos una foto y volvimos a la ruta.

No llegamos a Siracusa, llegamos a Catania.

Un detalle de Catania: las calles son casi todas angostitas, y hay mucho tráfico. Por ejemplo, encaramos por una feria callejera, y de golpe un tipo en una especie de Trafic simplemente encaró por el medio tocando bocina, confiando en el instinto de supervivencia Siciliano para no convertirse en asesino serial. Mujeres con carritos de bebé saltando adentro de los stands para que no las pisen, puesteros haciendo gestos obscenos al grito de basssssstarrrrdo!, cosas así. Y así llegamos a una plaza que según Lucio "es igual a Cuba", una iglesia hermosa cerrada y abandonada, pibes jugando a la pelota, montañas de mugre

Agradezcan que la foto no transmite la spuzza.

Pero eso no es nada comparado con la policía en Palermo. Los policías manejan Alfa Romeo. Y tienen sirena. Y el siciliano es algo así como una versión desinhibida del argento, así que en media hora pasaron tres patrulleros a 120 en una callecita medieval, con la sirena a todo dar porque debe ser re divertido.

En Catania probé mi primer canoli siciliano. Y disculpen que me pase el próximo párrafo hablando de lo que es, en el fondo, una simple factura. Igual que la venus de milo es una estatuita rota, igual que cualquier cosa hermosa, preciosa y casi perfecta es un ejemplo de una categoría que la degrada por comparación. Un canoli es una masa aireada, ligera, dulce, envolviendo crema pastelera, o jalea, o nutella, o queso, o casi cualquier cosa que sea blandita y deliciosa. He comido unos 30 canolis esta semana, y todos eran buenos. La parroquia de acólitos de la factura debería organizar peregrinaciones periódicas a Sicilia para que sus miembros puedan apreciar el ideal platónico de la factura. Que se quede París con sus patéticos croissants y sus infumables pain au chocolat. He saboreado el canoli y ahora entiendo perfectamente esto: Leave the gun, take the Canoli.

Pero bueno, paseamos por Catania, el centro es muy bello, hay una estatua horrorosa de un elefante, y nos fuimos a un hotel donde mi cuerpo dijo "llevo 48 horas andando sin parar" y procedió a pasarse a modo hibernación hasta la mañana siguiente.

Al día siguiente teníamos el vuelo a Malta desde Trapani que está ... sí, exactamente en la OOOOOOOTRA punta de Sicilia. Así que fuimos para ahí, y en el camino buscamos en internet algún lugar para ver que no nos desviara mucho. Encontramos Erice. Google nos decía "8km 35 minutos". Lo que Google no nos decía es que eran 35 minutos en cabra porque eso no era un camino para auto. Empezamos a subir por un caminito de montaña, bien pavimentado, pero muy empinado, lleno de curvas cerradísimas, y sin ningún auto. Y subía, y subía, y subía. Y después subía. Hasta que google nos dijo "derecha". Y eso llevaba a una huella de tierra en la cual no podíamos dar vuelta, y sin guarda rail del lado del precipicio. Ahí dijimos fuck google, y volvimos para atrás (30 metros marcha atrás en un camino de tierra a 50cm de un precipicio...) y fuimos a la izquierda. Llegamos al cementerio de Erice, seguimos y llegamos a Erice.

Claro, llegamos y estábamos "che, cuanto tardamos en llegar acá? 2 horas? Y cuanto falta para el avión?" asi que estuvimos un rato y volvimos por... EL OTRO camino a Erice, una autopista panorámica con vista al mar que Lucio se entusiasmó y la bajamos como si fuéramos en un Scalectrix mientras yo sentía que me salía el estómago por las orejas.

Llegamos a Trapani con media hora de margen, tomamos el vuelo de Ryanair y llegamos a Malta.

Para los que nunca hemos viajado en Ryanair, la primera vez puede ser un poco traumática. Es innegable que se vuela barato. Apenas 80 euros para un vuelo ida y vuelta internacional, es barato. Claro, tratan de ganar dinero por otros lados.

Si no pagás, te asignan el asiento al azar. Podés participar en una rifa que cuesta 2 euros y el viaje puede ser gratis. Si no te imprimis el boarding pass, sale 70 euros. Despachar una valija? Cuesta dinero. Si no la despachás y no te dejan llevarla en la cabina? Cuesta más dinero. No querés seguro? Tenés que elegir el país "Don't insure me", entre Denmark y Finland. Y así.

La cabina está sucia porque el avión llegó hace 10 minutos y no lo limpian entre vuelo y vuelo, así que uno barre las migas del asiento, pone el traste y ... la azafata se pasa el vuelo vendiendo cosas por el sistema de altavoces. "Mientras estamos en aguas internacionales, puede comprar Calvin Klein One 100ml por solo 58 euros!"... TODO EL VIAJE.

A favor: sale y llega a tiempo, es baratísimo, y podés usar electrónica todo el viaje.

Y así llegué a Malta, donde me pasé los siguientes días sin ver nada a más de 2 cuadras del hotel, hasta que junté fuerzas y salí un día a caminar un poco.

El viernes, antes de salir, decidí hacer una excursión de verdad y me fuí a M'dina, la ciudad silenciosa.

Y hasta acá me llegaron las ganas de escribir hace mucho tiempo, cuando estaba escribiendo esto. El resto del viaje estuvo bueno, volví bien.

FLOSS Decision Making in Action

If you are reading this there is a good chance you are involved somehow in open source development, or software development in general. One thing lots of people ask me when they know I have lead this sort of projects for a long time is "how do you decide things?". To which I have all sorts of bad answers like:

  • "It's a consensus thing"
  • "It happens organically"
  • "Sometimes it just happens"
  • "Anarchy!"
  • "You do what you do"

So, now here I have an AWESOME example of FLOSS decision making in action, which is ... all of the above.

Some context: Nikola is a static site generator, so it deals with reading and writing textual data from disk. It's also an internationalized project, which supports multilingual sites and translated data. It also runs un multiple platforms, like Windows, OSX, Linux, etc.

And to make that more fun, it also works on Python 2.7, and 3.3 or later. Which means it has to handle two different models on how to work with unicode data, in the same codebase. And that's not fun. So, we have been floating around the idea of deprecating python 2.7. And so, when s2hc_johan walks in with a unicode problem...

14:23:16 <s2hc_johan> I don't have a site with sections, but I tested it for the other case
14:35:42 <s2hc_johan> strange it worked for a while broken again, probably because I've got åäö in it now.
14:35:45 <s2hc_johan>
14:36:17 <s2hc_johan> if you wrap data with unicode it works, but I'm not sure that works in python3
14:36:37 <ChrisWarrick> s2hc_johan: how do you wrap it with unicode?
14:36:48 <s2hc_johan> unicode(data)
14:37:05 <s2hc_johan> but is that valid in  python3?
14:37:11 <ChrisWarrick> s2hc_johan: this is wrong on so many levels
14:37:16 <ChrisWarrick> s2hc_johan: please don’t do that, ever
14:37:48 <ChrisWarrick> s2hc_johan: This won’t work in Python 3 either.  You must have an actual encoding, and use the decode method.   try: foo = foo.decode('utf-8'); except AttributeError: foo = foo  # python 3
14:38:02 <s2hc_johan> what do you mean, that is like my standard when I get strnage data in, undoce(data) data.encode(whatever) data.decode(whatever) :)
14:38:23 <s2hc_johan> one of them ussually work
14:39:22 <ChrisWarrick> s2hc_johan: unicode() assumes ASCII, it never works right
14:39:32 <s2hc_johan> true
14:39:40 <ChrisWarrick> s2hc_johan: encode/decode with a specified encoding is fine
14:40:00 <ChrisWarrick> s2hc_johan: but you might need a try/except for Python 3 if it could have Unicode data already
14:40:16 <s2hc_johan> I'm a bit confused in this case since the output comes from json.dumps
14:40:34 <s2hc_johan> thought that would produce a unicode object
14:40:51 <ChrisWarrick> s2hc_johan: not necessarily on python 2
14:41:05 <ralsina_> if isinstance(thing, utils.str_bytes): thing=thing.decode('utf8')
14:41:15 <ralsina_> that works in py2 and py3
14:42:12 <ChrisWarrick> easier to ask for forgiveness imo
14:43:07 <ralsina_> maybe we should have helpers in utils enforce_unicode and enforce_bytes
14:43:13 -GitHub[nikola]:#nikola- [nikola] Aeyoun pushed 1 new commit to feed-previewimage:
14:43:13 -GitHub[nikola]:#nikola- nikola/feed-previewimage 4b79e20 Daniel Aleksandersen: Deprecated RSS_READ_MORE_LINK and RSS_LINKS_APPEND_QUERY...
14:44:58 <Aeyoun> Or upgrade to Py3.
14:45:11 <ChrisWarrick> ++
14:45:47 <Aeyoun> Unicode in Py27 is a nightmare. It tries as hard as it can to kill you at every turn.
14:48:09 -travis-ci:#nikola- getnikola/nikola#6426 (feed-previewimage - 4b79e20 : Daniel Aleksandersen): The build is still failing.
14:48:10 -travis-ci:#nikola- Change view:
14:48:10 -travis-ci:#nikola- Build details:
14:48:27 <ralsina_> ok, let's consider py3-only seriously.
14:48:40 <ralsina_> 1) Is there any distro commonly used with py3 < 3.3 ?
14:48:55 <ralsina_> 2) Do we just stop using py2, or we deprecate slowly?
14:49:15 <ralsina_> 3) Do we just start doing py3-only code, or we actively de-hack the codebase?
14:49:21 <ralsina_> That's my 3 questions :-)
14:50:13 <SteveDrees> Unicode is a nightmare
14:50:53 <SteveDrees> different python versions just changes where the pain point is
14:50:53 <s2hc_johan> which one is better isinstance... or hasattr('decode', ..)
14:51:02 <ralsina_> isinstance
14:51:08 <s2hc_johan> oki then
14:51:10 <ralsina_> hasattr is evil in itself
14:51:26 <s2hc_johan> just going to feed the kids then I'll make another pr
14:51:28 -GitHub[nikola]:#nikola- [nikola] Aeyoun pushed 1 new commit to feed-previewimage:
14:51:28 -GitHub[nikola]:#nikola- nikola/feed-previewimage 4c950ac Daniel Aleksandersen: flake8
14:52:13 <Aeyoun> ralsina_: user survey? pip download data?
14:52:33 <gour> ralsina_: create some poll at website/mailing-list about it?
14:53:18 <ralsina_> dude, I offered free shirts and I got only 10 requests ;-)
14:53:30 <ralsina_> so, how many answers do you expect about that sort of thing?
14:53:43 * gour thought shirts are jsut for devs :-(
14:53:47 <Aeyoun> ralsina_: release a unchanged version on pip that is flagged as py3 only. see how many downlaod it versus previous version in same amount of time.
14:53:51 <ralsina_> gour: go add yourself dude
14:54:18 <ralsina_> gour: TO THE SHIRT LIST! I just notced that sounded very rude :-)
14:54:43 <gour> ralsina_: where it is?
14:54:43 <Aeyoun> ralsina_: or one py27 version number and and one version py3 only version number at the same time.
14:55:17 <ralsina_> gour:
14:55:17 <gour> found it
14:56:00 <gour> ralsina_: wonder if xxl is too large or xl is enough
14:56:00 <Aeyoun> ralsina_: american or european sizes by the by?
14:56:03 <ralsina_> Aeyoun: that reflects how many people use py2.7 by reflex. I know *i* do because it's "python" and not "python3"
14:56:20 <ralsina_> Aeyoun: no idea about sizes to be honest... probably american
14:56:21 <Aeyoun> American sizes are … a big bigger. I’m probably a XS/S american but M european. :P
14:56:28 <Aeyoun> *bit bigger
14:56:39 <gour> ok
14:56:57 * gour submitted request
14:57:17 <ralsina_> So, what I would prefer to do is make people use py3 if they can. And it seems to me that pretty much everyone can, regardless of whether they still use py2 by defect.
14:57:26 <ralsina_> by default*, spanishism leaked there.
14:57:52 <ChrisWarrick> technically, using py2 is a defect
14:57:59 <ralsina_> So, if we all agree that most users *could* run nikola in py3... then let's do it.
14:58:02 <Aeyoun> Agreed.
14:58:15 <gour> sites won't stop working :-)
14:58:26 <Aeyoun> ralsina_: act on data not dev agreement?
14:58:42 <ChrisWarrick> guess we could change our docs/webiste to highlight 3.x
14:58:59 <ralsina_> Aeyoun: the only data we'd need is to know how many people have py2.7 and no py3.3
14:59:14 <ralsina_> not how many are *using* 2.7 instead of 3.3
14:59:38 <ChrisWarrick> micro-survey via ml?
14:59:39 <ralsina_> How about: let's announce that, unless lots of people complaint, we deprecate py2 by end of october
14:59:45 -travis-ci:#nikola- getnikola/nikola#6429 (feed-previewimage - 4c950ac : Daniel Aleksandersen): The build was fixed.
14:59:46 -travis-ci:#nikola- Change view:
14:59:46 -travis-ci:#nikola- Build details:
14:59:47 <Aeyoun> Mac is shipping with Py2.7 and no Py3. BUT MacPorts and Homebrew offer painfree Py3 installs.
14:59:58 <ralsina_> ok, mac is a good point
15:00:25 <ChrisWarrick> it’s not like we have Homebrew/MacPorts/Fink-based install instructions for them…
15:00:27 <Aeyoun> ralsina_: we could add a deprecation message every time `nikola` is run and ask people to bitch in a bug?
15:00:32 <Aeyoun> ChrisWarrick: hehe. ;)
15:00:50 <ralsina_> "I see you have python3 installed but I am running on 2.7 ... dude, what's wrong with you?"
15:00:51 <Aeyoun> Or maybe once per 24 hour rather  than every time its run.
15:01:00 <ralsina_> doit timed tasks :-)
15:01:12 <Aeyoun> ralsina_: "Don’t get in the way of progress! Upgrade to Py3 and save a developer’s mind today!"
15:01:32 <ralsina_> "niec unicode you have there, would be a shame something happened to it.. switch to python 3!"
15:01:39 <ChrisWarrick> ralsina_: hey, let’s start with a Google Docs survey on the ML.  One question: what Python version and OS are you using for Nikola? 2.7/3.3/3.4/3.5; Windows/OS X/[other: linux/bsd distro]
15:01:57 <gour> "Free t-shirt foreveryone switching from py2.7 to py3.3"
15:01:58 <ChrisWarrick> ralsina_: Just don’t require a Google account like you did last time.
15:02:00 <ralsina_> Second question: "Do you have python 3.3 or later installed?"
15:02:03 <Aeyoun> How much code can be removed with dropping Py27? Lowers maintenance cost and increases performance. That is also an important datapoint.
15:02:11 <ralsina_> ChrisWarrick: I needed to know who was asking for the shirt :-)
15:02:21 <ChrisWarrick> ralsina_: good point
15:02:25 <ralsina_> Aeyoun: not all that much, really
15:02:47 <ChrisWarrick> Aeyoun: it would need to start with a huge rewrite to remove all of our pointers in nikola.utils
15:03:00 <ralsina_> Aeyoun: there are a number of tiny hacks, which were a pain to get right but they always amount to one if and/or one decode :-)
15:03:26 <ralsina_> We can just turn a bunch of helpers in utils into noops
15:04:52 <gour> py3-only nikola is going to become v8?
15:05:15 <Aeyoun> gour: seems like a likely outcome. you’re following the discussion live.
15:06:34 <ChrisWarrick> if we do v8, we’ll have to merge the early tasks garbage
15:07:03 <ralsina_> Is it technically backwards-incompatible if we just stop working on py2.7?
15:07:21 <ralsina_> gour: welcome to open source software: behind the code.
15:07:30 <gour> ralsina_: :-)
15:07:35 <Aeyoun> Someone call in a documentary crew!
15:07:43 <ralsina_> Aeyoun: we have logs!
15:07:51 <Aeyoun> Oh, wait. This is already logged for prosperity.
15:07:57 <ralsina_> I am totally posting this somewhere as "this is how decisions are made in FLOSS"
15:08:40 <ralsina_> Ok, who creates the poll and who posts it in the blog, and who makes sure it appears on planet, and who sends it to the list?
15:08:49 <ralsina_> I would do it but I have work to do :)
15:08:51 <ChrisWarrick> ralsina_: I’ll do it
15:08:57 <ralsina_> ChrisWarrick: you rock dude!
15:09:01 <ChrisWarrick> ralsina_: should be really simple
15:09:03 <ralsina_> Ok, we have a plan!
15:09:17 <ralsina_> Let's consider the poll results in ... a week?
15:09:25 <Aeyoun> Let the logs show we’re all in favor of this plan of action. ;-)
15:09:29 <ralsina_> aye
15:09:51 <ralsina_> Also: can I do the "shame on you" thing on nikola build? It sounds like fun :-)
15:10:27 <ChrisWarrick> ralsina_: for the python version question: radiobox vs checkbox?
15:10:28 <gour> ralsina_: you can mention that Nikola (Tesla) was always for innovation ;)
15:10:44 <Aeyoun> "You’re using FIVE YEAR OLD SOFTWARE. Update your system."
15:11:00 <ralsina_> Aeyoun: I am totally getting at least 5 different comments there
15:11:01 <Aeyoun>
15:11:05 <ralsina_> ChrisWarrick: checkbox... maybe 2?
15:11:23 <ralsina_> ChrisWarrick: one for python version, one for operating system
15:11:32 <ChrisWarrick> ralsina_: ?
15:11:38 <ralsina_> ChrisWarrick: two questions
15:11:54 <ChrisWarrick> ralsina_: there will even be three questions (py2/3 used, OS, has py3)
15:11:57 <ChrisWarrick> ralsina_: and checkboxes it is
15:12:02 <ralsina_> right
15:12:05 <ralsina_> awesome
15:14:44 <ralsina_> Copied / Pasted for posterity

There you go, half an hour later, we have a plan to (maybe) deprecate it.

Now go vote here: Should Nikola support python2.7? Gives us data to decide!

Carrio, Abal Medina, y La Fafafa

Cuando leí lo que Carrió había dicho de Abal Medina, me hacía acordar a algo. Esto es lo que dijo Carrió:

Carrió dijo que José Luis Gioja, gobernador de San Juan, pidió que "no le manden más a Abal Medina porque estaba drogado". -- Diversos medios

Me hacía acordar a algo, porque hace como dos años había leído una cosa similar, originada en un sitio de mano de obra desocupada especializada en difamar gente, llamado SEPRIN:

"El portador de las indicativas era el Jefe de Gabinete Juan Manuel Abal Medina, pero su llegada a San Juan se pareció –según dijo el propio gobernador- al Charly García de sus peores tiempos. Duro, como “plastificado”, los ojos abiertos y enrojecidos como quien no está en sus cabales y fundamentalmente sin poder articular palabra alguna." ...

"Gioja lo tomó del hombre y le pidió a Abal Medina que se volviese, que era una vergüenza el estado lamentable en que se encontraba, que si los periodistas se daban cuenta que estaba pasado de sustancias ilícitas le daría argumentos servidos en bandeja a la oposición."


Es una burda operación de prensa, dado que por un lado menciona que es una cumbre de gobernadores en Corrientes, pero por otro lado habla de que Abal Medina "[llegaba] a San Juan". Pero hay bastantes coincidencias, lenguaje similar, los mismos protagonistas.

Esa cumbre de gobernadores peronistas fue el 1/9/2013. Poco tiempo después, el 11/10/2013, Gioja sufre un terrible accidente de helicóptero, queda en coma e incapacitado por mucho tiempo.

Estando Gioja internado y apenas saliendo del coma, es visitado por Abal Medina el 17/10/2013:

"El Jefe de Gabinete, Juan Manuel Abal Medina, llegó esta mañana a la provincia para interiorizarse del estado de salud del gobernador Gioja y para ponerse a disposición de la familia del primer mandatario provincial.

“Estamos muy contentos, la familia nos acaba de contar que evoluciona muy bien. Hoy reconoció a su mujer, le preguntó si le podía dar un beso y él le dijo que sí”, relató ante la prensa el funcionario nacional quien también destacó que su visita es en representación de todas las autoridades nacionales."

Diario de Cuyo

A esa visita se refiere Gioja cuando dice que esa fue la única visita de Abal Medina a San Juan siendo Jefe de Gabinete, ya que un mes después, Abal Medina es reemplazado por Capitanich el 19/11/2013

Teniendo en cuenta el orden de los eventos y las fechas, creo que es sumamente improbable que Carrió se refiriera a otra ocasión en que Gioja hablara así de Abal Medina.

En consecuencia, creo que es bastante obvio que Carrió no hacía más que repetir el pescado podrido de SEPRIN.

Y por las dudas, si creen que lo de SEPRIN es cierto, veamos una cosita que dice la "nota":

[Abal Medina estaba] Duro, como “plastificado”, los ojos abiertos y enrojecidos como quien no está en sus cabales y fundamentalmente sin poder articular palabra alguna.

Y acá lo tienen a Abal Medina, en esa "cumbre de gobernadores" (desde el minuto 3:50). A mí no me parece que esté muy drogado...

Así que ya saben: Carrió probablemente repite "noticias" levantadas de sitios de muy dudosa reputación, y en base a eso le tira mierda a la gente.


Carrió afirma haber visto a Abal Medina totalmente drogado en el Congreso. Probablemente se refiere a esta sesión de Julio del 2012, lo dejo a su criterio:

Some New Stuff in Nikola

I did some quick work on Nikola (a static website/blog generator) lately, after a long time, and here's what it was:

Multilingual Sitemaps

So, sitemaps are used by Google to index your site. It turns out that they can describe when there are sets of pages that are translations of each other. So the next release will do that (Issue #1610)

Matplotlib Plots

Matplotlib comes with a sphinx extension to do plots So I went and implemented it, this was Issue #1242 and it's a plugin called pyplots, which will be soon at

I hated the original code. It felt convoluted, and just weird (it's probably just me) so I wrote it from scratch and it has some minor differences, but it's fairly compatible.

Classy Images

The docutils image directive, for whatever reason, doesn't support a class option, so you need to do things like this:

.. class:: foo

.. image:: blah.png

Which is ... not pretty. So I did a hacky plugin that monkeypatches the image directive to add that option. The plugin is at and this fixes Issue 1538

Mediawiki Markup

djbclark pointed out that there is a library to parse MediaWiki from python called so I implemented a plugin to use it, so now you can use MediaWiki markup. The plugin is at

Removed Default Swatch from Bootswatch

This was Issue #1656 and now you have to specify the swatch. This is a usability fix, because defaults matter.

Played with KaTeX

Nikola supports math using MathJax. MathJax has some interesting qualities:

  • It's 160MB of code or so
  • It's not practical to use without a CDN
  • It's not practical to use webasset bundles with it

Then, klingtnet mentioned something called KaTeX I had never heard about. I did a quick hacky conversion to see how it works. Not done yet, totally experimental, but it may be possible to bundle it, and maybe even have it turned on by default, removing the need for the mathjax label which is awful usability-wise.

Some of these things are merged, some are still PRs, some are in core, some are plugins. They were all pretty fun to do :-)

El Sutil Arte de Citar

Los periodistas televisivos suelen tener un cierto complejo de inferioridad con los que medios impresos. Por eso solés ver gente que conduce exitosos ciclos políticos recordar que ellos el periodismo lo mamaron en la redacción del semanario "El Mangrullo" de Venado Tuerto, y que eso de ganar mucha guita apareciendo en tele lo hacen porque no les queda otra.

De ahí que cuando (ponéle) Majul hace una nota y la levanta un medio impreso, siempre la retwitea. Por ejemplo, acá muestra, orgulloso, que su nota es citada por el Cronista Comercial:

Ahora bien, si uno va y lee la nota... resulta que dice exactamente lo contrario que el título.

Cito la nota:

"Con Rabbani no tenemos ningún intercambio de dinero."

Sí admite recibir dinero de Irán:

Muchas veces las universidades de Teherán contribuían con nosotros y le decíamos "necesitamos tanto para hacer el trabajo religioso"

Sin embargo, Irán no es Rabbani, y Rabbani no es Irán. No tengo idea de si Khalil recibe dinero de Rabbani, y no es de lo que estoy hablando en este momento. Lo que sí veo es que no lo dijo. Y que ese título es mentira, y el tweet es mentira, y Majul repite una mentira.

Y lo hace a sabiendas.

Como diría Luis Majul... ¿Que sentís, Luis Majul?

La Escalada Honestística

Anoche ví Animales Sueltos, el programa de Fantino. Lo primero es felicitar a quien corresponda, sea Fantino, América TV, o el público, que ha convertido un programa donde Coco Sily seguía afanando con "La cátedra del macho" ad eternum en un programa de entrevistas políticas.

Será criticable, Fantino tendrá la actitud entrevistadora más irritante del universo ("explicame como a un niño" !?!) pero es mejor, en el sentido de más importante, que escuchar chistes de borrachos (en el sentido de chistes que parece que los contara un tipo borracho).

Más allá del racismo ocasional ("eso pasa en países como Uganda, Nigeria"), ayer tuvo dos entrevistas interesantes, una con Ernesto Sanz, el último exponente de que eso de que la UCR no se dobla era verso, y De Narváez, el último mohicano menemista.

Y una de las cosas interesantes, fue que le preguntó la misma cosa a los dos. ¿Cuánto creen que se robó durante el kirchnerismo?.

Primero, Sanz tiró "más de mil millones de dólares".

Y como decir lo mismo o decir menos no tiene gracia, De Narváez salió a escalar. Esta es la cuenta que sacó:

  1. El PBI de Argentina es 300 mil millones de dólares.
  2. El presupuesto del estado nacional es la mitad, 150 mil millones de dólares.
  3. Se roba por lo menos el 10% del presupuesto
  4. Se robaron 15 mil millones de dólares.

Eso es mucho, pero De Narváez se olvidó de multiplicarlo por los años que llevan en el gobierno, con lo que la cifra, en realidad, sería de 180 mil millones de dólares.

Cabe destacar que eso es sin contar corrupción a nivel provincial y municipal, pero bueno, no inflemos más de lo que infló él.

Lo que cuesta, tal vez, entender, es exactamente cuanta plata es eso. Así que veamos algunos ejemplos.

Con 250.000 dólares te comprás una linda casa, en un lindo barrio. Esa plata alcanza para 720.000 casas así. Eso es más que la cantidad de inmuebles de la Ciudad Autónoma de Buenos Aires.

Según, con 1.000.000 de dólares te comprás unas 150 hectáreas en Carlos Casares, plena pampa húmeda. Eso quiere decir que con lo que dice De Narváez, se pueden comprar 27 MILLONES de hectáreas en la pampa húmeda. Eso es el 90% de la provincia de Buenos Aires.

En Argentina hay, mas o menos, 40 millones de personas. Esa plata alcanza para darle 4500 dólares a cada hombre mujer y niño del país.

Un paquete de 100 billetes de 100 dólares (o sea, 10.000 dólares) mide 15.24cm x 5cm x 1.1cm. Si apilamos la plata que dice De Narváez, da una altura de 198 km.

¡Claro, podemos acomodarla mejor! El volumen de ese dinero es 1.508.760.000 centímetros cúbicos, o, redondeando, un millon y medio de litros. Es decir que podemos llenar una pileta olímpica hasta más de la mitad, suponiendo que no dejamos ningún espacio entre billetes.

O, podríamos llenar 22.3 containers standard de 40 pies, si cada uno tiene un volumen interno de 67,5 metros cúbicos como dice Wikipedia.

Un billete de 100 dólares pesa exactamente un gramo, así que en total son 1800 toneladas de dinero. Para transportar ese dinero se necesitan 3 aviones Jumbo de carga.

Ahora bien: si realmente usted cree que Nestor y Cristina afanaron esa cantidad de dinero...

Piénselo, y trate de compatilizar esa cantidad de dinero con su teoría conspirativa de cabecera. Entonces, una vez que entienda cuanto dinero es esto...

  1. También creés que lo tenían/tienen guardado en una bóveda en la casa?
  2. También creés que la valija de Antonini Wilson con 800.000 dólares les importaría?
  3. También creés que lo sacaron en valijas en aviones de línea por arreglos con la aduana?
  4. También creés que necesitan que Báez les pague un milloncito de pesos por algo?

No espero que nadie abandone sus teorías. Tan sólo me conformo con que mejoren su consistencia interna.