Older blog entries for ralsina (starting at number 502)

Dear Dr. Sheldon Cooper...

http://imgs.xkcd.com/comics/duty_calls.png

This post is a joke.

Dr. Cooper, I hope this letter fids you in good health. I couldn't avoid overhearing you talk with Dr. Hofstadter on our building's staircase the other day.

I am speaking about when you mused about how life would be if people evolved from reptiles. I am so disappointed in you.

First, you mention that lizards are cold-blooded. Which is true. And that when it's cold they get slower. Which is also true. But then you sayd something like "the weatherlizard would say 'it's slow outside' instead of 'it's cold'".

POPPYCOCK Dr. Cooper! If the lizard is slow because it's cold, it would perceive everything out there as fast, not slow, just like slow cars see faster cars as, you know... fast?

Also, the mention about suggesting the lizard should wear a sweater is a slap on the face of physics. Sweaters are an insulator, not an energy source. What makes the inside of the sweater warm is the human, Dr. Cold-blooded lizards would have no such effect beyond the tiny thermal inertia such an imperfect wool insulator would allow.

If you are interested on further argument in human-like reptile civilization and folklore I will be happy to indulge, but I must say I expected better of you.

Mrs. Vartabedian.

PS: things like this are the reason why I never ask you to come home for cereal.


Syndicated 2012-03-12 03:14:43 from Lateral Opinion

Fatter

'Thinner,' the old Gypsy man with the rotting nose whispers...

—Richard Bachman (Stephen King)

I was not always fat. I used to be really, really thin. So thin that when I was 16, my motherforced me to eat. I was 1.75 and weighted about 65 kilos when I finished highschool. So thin I used M sized shirts until I was 25.

That has, as those who know me can agree with, changed quite a bit. I broke the 100kg bareer 10 years ago or so, and reached 123.5Kg earlier this week. Also, I am not 3.5 meters tall, so I am close to having doubled my weight and body mass in these 25 years.

That is not a good thing. It's such a bad thing, that my doctor has explained to me that if I don't lose a lot of weight soonish, I am going to fucking go and die. Not next week, not next year, but not in 40 years either.

Since my weight started going up while I was in college and my dad was sick, I always blamed some anxiety problem, eating crap, a sedentary lifestyle, the usual suspects.

So, I got some tests done. Turns out I was more or less right. The "more" is because I do have to stop eating crap, and I need to exercise more. The "less" is because I have (among other things) hyperinsulinemia. Wanna guess what are the most visible symptom of that?

  • High blood pressure (on medication since 5 years ago)
  • Increased VLDL (diagnosed 2 years ago)
  • Lethargy (fuck yes)
  • Weight gain (double fuck yes)

And what does weight gain of this kind do to you? A lot of other bad things.

Since tuesday I am on a very specific diet, and taking a drug to reduce my insulin production (Metformin). I am feeling active, and have lost 3 kilos in 4 days (yes, I know that is not a sustainable rate and will plateau).

My feet stopped swelling.

I am not hungry all day.

I am walking 30 minutes, twice a day.

I want to code.

I feel good. I have felt better, when I started taking BP meds, I have felt worse when my liver function decreased, I have felt very bad, when my BP spiked, but good? I have not felt good in a very, very long time.

This may not be the drug or the diet. Maybe it's placebo effect. Maybe it's something else. On the other hand, I have decided that my life is too sweet to drop dead right now. So, let's see how this goes.


Syndicated 2012-03-11 01:54:27 from Lateral Opinion

1003 is a funny number, just not funny haha

In 1003, Erik the Red died after having ruled Greenland. Which of course, was a bad idea, color-combination-wise.

http://piachepiu.com.ar/wp-content/uploads/2011/08/KKC4250.jpg

Article 1003 at piachepiu.com.ar

Also a bad idea was decree 1003/89 which pardoned every "subversive" or "terrorist", including those dead or disappeared. This is after decree 1002, that pardons those who killed or disappeared them, of course.

Much milder is decree 1003/98 which gives an award to Roberto DeVicenzo. I wrote a program called devicenzo, BTW.

http://sp270.fotolog.com/photo/27/20/74/linea91_150/1267667784122_f.jpg

Car 1003 of the 56 bus.

Bug #1003 in launchpad is about launchpad, the title is "projects +search page 404" and the description is "Page not found Page not found". It's fixed.

If you search for 1003 in Google Maps, it gives you one result, in Latvia.

1003 days ago, it was september 15th, 2002, the day of my 31st birthday.

http://upload.wikimedia.org/wikipedia/commons/thumb/e/e0/Albatross_%28American_Motor_Boat%2C_1912%29.jpg/300px-Albatross_%28American_Motor_Boat%2C_1912%29.jpg

USS Albatross, SP-1003

Page 1003 of Gray's anatomy is about the development of the eye and contains a drawing of "the eye of an eighteen days’ embryo rabbit.".

http://www.visionembroidery.com/components/com_virtuemart/show_image_in_imgtag.php?filename=1003_Rabbit_Skin_49d05d18b2535.jpg&newxsize=240&newysize=320&fileout=

"1003 Rabbit Skins Snap Bib" (scary!)

Page 1003 of "Familiar Quotations, 10th ed of 1919" says "We are dancing on a volcano.", attributed to the Comte de Salvandy. Alto del Zapote, in Cuba is 1003 meters tall, but is not a volcano at all.

http://www.kopernik.org/images/archive/n1003.jpg

NGC 1003, a diffuse spiral galaxy in Perseus.

Oh, and this blog has 1003 posts.


Syndicated 2012-03-07 02:37:54 from Lateral Opinion

So, rst2pdf is now 0.91

Turns out there was a major, show stopper bug in rst2pdf 0.90: sphinx support was absolutely broken. Not broken as in buggy, broken as in it had syntax errors.

So, 0.91 is now released, and only broken in the traditional sense. Enjoy!


Syndicated 2012-03-06 02:40:57 from Lateral Opinion

rst2pdf 0.90 is out

Yes, after many moons, it's out. Here is the (as usual) incomplete changelog:

  • Added raw HTML support, by Dimitri Christodoulou
  • Fixed Issue 422: Having no .afm files made font lookup slow.
  • Fixed Issue 411: Sometimes the windows registry has the font's abspath.
  • Fixed Issue 430: Using --config option caused other options to be ignored (by charles at cstanhope dot com)
  • Fixed Issue 436: Add pdf_style_path to sphinx (by tyler@datastax.com)
  • Fixed Issue 428: page numbers logged as errors
  • Added support for many pygments options in code-block (by Joaquin Sorianello)
  • Implemented Issue 404: plantuml support
  • Issue 399: support sphinx's template path option
  • Fixed Issue 406: calls to the wrong logging function
  • Implemented Issue 391: New --section-header-depth option.
  • Fixed Issue 390: the --config option was ignored.
  • Added support for many pygments options in code-block (by Joaquin Sorianello)
  • Fixed Issue 379: Wrong style applied to paragraphs in definitions.
  • Fixed Issue 378: Multiline :address: were shown collapsed.
  • Implemented Issue 11: FrameBreak (and conditional FrameBreak)
  • The description of frames in page templates was just wrong.
  • Fixed Issue 374: in some cases, literal blocks were split inside a page, or the pagebreak came too early.
  • Fixed Issue 370: warning about sphinx.addnodes.highlightlang not being handled removed.
  • Fixed Issue 369: crash in hyphenator when specifying "en" as a language.
  • Compatibility fix to Sphinx 0.6.x (For python 2.7 docs)

This release did not focus on Sphinx bugs, so those are probably still there. Hopefully the next round is attacking those.


Syndicated 2012-03-04 17:40:16 from Lateral Opinion

Extendiendo rst2pdf y sphinx

Sorry, spanish only post!


Estimado público lector, una cosa muy especial: un post que no escribí yo! Démosle una bienvenida al autor invitado, Juan BC!


Una de mis promesas en el año fue terminar uno de los proyectos mas ambiciosos que me había propuesto: terminar mi ambientación de rol utilizando el sistema matemático que había diseñado junto con un amigo tiempo atras llamado Cros aprovechando la barbaridad de imagenes que tenía guardada de mi tesis de grado.

Como no puede ser de otra manera como miembro de Python Argentina utilice el programa utilizado por rst2pdf creado por Roberto Alsina el cual es el dueño de este blog

En un punto necesitaba hacer una especie de plantillas de dibujos para repetir el estilo donde hay descripciones de un personaje pero el estilo se mantiene, como por ejemplo las tarjetas de este manual de DC Universe RPG :

/static/cards_dc.jpg

y me dije a mi mismo

¿Por que demonios no puedo dibujar un svg_ dejar espacios en blanco y luego los lleno dentro del svg?

En definitiva, me imaginaba algo así:

.. template_svg: path/a/mi/archivo/svg/que/tiene/las/variables/definidas/adentro.svg
    :nombre_variable_1: valor_de_variable_1
    :nombre_variable_2: valor_de_variable_2
    ...
    :nombre_variable_N: valor_de_variable_N

Entonces me puse en campaña para poder programar el código python que realiza esa tarea como una extensión de rst2pdf.

AVISO!!! este texto lo llevara a usted por cada una de las desiciones de diseño que involucran la creación de mi extensión para rst2pdf

Definiendo sintaxis y comportamiento

Por empezar aprendí de las limitaciones de la directiva, decidí un nombre para ella y definí cual era el comportamiento que hiba a tener.

  • Dado que una directiva como template_svg me sonaba a larga decidí que el nombre sería svgt (SVG template).

  • Las directivas soportan parámetros fijos, no puedo tener un número variable de argumentos para pasarle: nombre_variable_1, nombre_variable_2, variable_N a algo como directiva(**kwargs).

    Mi solución fue pasarle todo en un json.

  • Por último definí que svgt generaría un nodo de tipo figure con lo cual mi directiva aceptaría, además de mis parámetros, los argumentos que ya tenía incorporados en dicha directiva.

    Esta última decisión me llevó también a contemplar que el archivo svg debería convertirse en un png, y para esto utilizaría la herramienta Inkscape con una llamada al sistema para realizar dicha conversión (la gran ventaja de inkscape es que puede correr totalmente headless con el parámetro -z).

En definitiva mi directiva tomaría un nodo asi:

.. svgt:: file.svg
    :vars:
        { "nombre_variable_1": "valor_de_variable_1",
          "nombre_variable_2": "valor_de_variable_2",
          ...,
          "nombre_variable_N": "valor_de_variable_N"}

     <figure parameters>

Y lo convertería en un nodo así

.. figure:: file_con_parametros_resueltos.png
    <figure parameters>

Creando el template

Yo uso para crear svg a Inkscape y no pensaba en ningún momento dejar de hacerlo para crear este proyecto. Así que solo era cuestión de abrir el programa y poner en la parte de donde se referencia a una url de una imagen o en un texto algún formato que indique que eso es una variable (recordemos que por dentro el svg no deja de ser texto plano).

Para elegir el lenguaje de template decidí utilizar el formato que propone la clase Template que viene en la librería estandar de; la cual dispone que las declaraciones de hacen anteponiendo el símbolo $ al nombre de la variable y pudiendo o no este nombre estar encerrado entre { y }.

Por ejemplo en el siguiente imagen se ve como declaro dos variables con Inkscape

/static/making_template.jpeg

Por otra parte inkscape desde consola se ejecuta de la siguiente manera para convertir un svg a png

::
$ inkscape -z file.svg -e file.png -d 300

Donde:

  • inkscape es el comando para correr inkscape.
  • -z sirve para deshabilitar el entorno gráfico.
  • file.svg es el archivo a convertir.
  • -e file.png indica que se va a exportar el archivo file.svg al formato png y se guardara en el archivo file.png.
  • -d 300 dice que el archivo file.png se creara con 300 dpi de calidad.

Con esto me genero los siguientes problemas:

  • ¿Qué sucede si otro me pasa un template y no se cuales son las variables que tiene adentro?
  • ¿Y si inkscape no está en el path de ejecución?
  • ¿Y si no me gustan los 300 dpi de calidad?

A este punto usted lector ya se dara cuenta que todo se trata de agregarle mas variables a nuestra sintaxis ya definida: con lo cual todo este cachibache quedaría así:

.. svgt:: file.svg
    :vars:
        { "nombre_variable_1": "valor_de_variable_1",
          "nombre_variable_2": "valor_de_variable_2",
          ...,
          "nombre_variable_N": "valor_de_variable_N"}
    :dpi: 72
    :inkscape_dir: /usr/bin
    :list_vars_and_exit:

     <figure parameters>

Siendo:

  • :dpi: 72 dice que el archivo generado para la figura resultante tendra 72dpi.
  • :inkscape_dir: /usr/bin indica que el comando inkscape vive dentro de la carpeta /usr/bin
  • :list_vars_and_exit: establece que svgt solo listara por stdout la lista de variales existente dentro de file.svg y luego el programa terminara (notese que solo tiene motivos de debuging).

En código python sólo hay que crear un string con esos huecos y luego llenarlos como en el siguiente ejemplo:

import os
cmd = "{isp} {svg} -z -e {png} -d {dpi}"
print cmd.format(isp=os.path.join("/usr/bin/", "inkscape"),
                 svg="file.svg",
                 png="file.png",
                 dpi="72")

[out] /usr/bin/inkscape file.svg -z -e file.png -d 72

A los bifes

Ahora si leyendo el manual de como crear directivas para docutils uno se encuentra que el esqueleto mínimo para crear estos bichos es el siguiente:

# imports necesarios
from docutils import nodes
from docutils.parsers.rst import directives
from docutils.parsers.rst import Directive
from docutils.statemachine import StringList

# la directiva es una clase
class SVGTemplate(Directive):
    """ The svgt directive"""

    # cuantos argumentos obligatorios tenemos
    required_arguments = 0

    # cuantos argumentos opcionales
    optional_arguments = 0

    # si la directiva termina con una linea en blanco
    final_argument_whitespace = False

    # funciones de validación para los argumentos
    option_spec = {}

    # si puede tener mas rst adentro de la directiva
    has_content = True

    # método que hace el procesamiento
    def run(self):
        return []

# le pone nombre a la directiva y la registra
directives.register_directive("svgt", SVGTemplate)

Los parámetros

Primero empecemos definiendo un diccionario que relaciona cada nombre de parámetro (los cuales yo defino que son TODOS opcionales) con una función que los valida. Por otra parte dado la estructura que queremos generar de figure posee contenido y la nuestra también debe poseerlo.

import json

# docutils imports

SPECS = {

    # variables mías y funciones que la validan y convierten en datos utiles
    # para nuestro procesamiento

    # convierte vars a un json
    "vars": json.loads,
    # convierte dpi a entero positivo
    "dpi": directives.nonnegative_int,
    # preprocesa el directorio quitandole espacios finales e iniciales
    # en blanco
    "inkscape_dir": directives.path,
    # se fija que por ser una bandera no tenga ni un valor asignado
    # si eso sucede retorna None sino tira un ValueError
    "list_vars_and_exit": directives.flag,

    # variables de figure
    "alt": directives.unchanged,
    "height": directives.length_or_percentage_or_unitless,
    "width": directives.length_or_percentage_or_unitless,
    "scale": directives.percentage,
    "align": lambda align: directives.choice(align, ('left', 'center', 'right')),
    "target": directives.uri,
    "class": directives.unchanged,
    "name": directives.unchanged,
    "figwidth": directives.length_or_percentage_or_unitless,
    "figclass": directives.unchanged,
}

# la directiva es una clase
class SVGTemplate(Directive):
    """ The svgt directive"""

    required_arguments = 0

    # cuantos argumentos opcionales
    optional_arguments = len(SPECS)

    final_argument_whitespace = False

    # funciones de validacion para los argumentos
    option_spec = SPECS

    has_content = True

    def run(self):
        return []

directives.register_directive("svgt", SVGTemplate)

Todas las funciones de validación (menos json.load) estan muy bien explicadas en la documentación de docutils .

Entendiendo los Nodos

La creación de nodos se hace con funciones que habitan en el modulo from docutils import nodes y todos los nodos se crean así (tomando de ejemplo figure):

my_new_node = figure(self, rawsource='', *children, **attributes)

donde:

  • rawsource: es el codigo fuente del nodo que sirve para motivos de debuginng, si salta un error te muestra donde esta la falla basandose en este string. Así que mientras mas representa al nodo este argumento mejor.
  • *children: son los nodos hijos.
  • **attribute: los atributos y opciones del nuevo nodo. si se pasa una opcion invalida simplemente se ignora.

Entendienfo figure

Las figuras son un nodo que contiene 3 hijos:

  • image que contiene la imagen propiamente dicha.
  • caption que es un párrafo que le da una etiqueta a la imagen.
  • legend que contiene todo los parrafos sobrantes que no son el caption

Osea algo asi:

+---------------------------+
|        figure             |
|                           |
|<------ figwidth --------->|
|                           |
|  +---------------------+  |
|  |     image           |  |
|  |                     |  |
|  |<--- width --------->|  |
|  +---------------------+  |
|                           |
|The figure's caption should|
|wrap at this width.        |
|                           |
|Legend                     |
+---------------------------+

Con esto en mente y con el concepto de que TODO NODO DEBE SER PROCESADO O DESTRUIDO MANUALMENTE vamos ya a encarar el algoritmo.

Explicando el método run

La función run sólo tiene una condición: debe devolver un lista que contiene nodos de docutils a ser renderizados

Así que a mano alzada run sería algo mas o menos así:

def run(self):
    # sacamos la direccion donde se encuentra el svg
    uri = self.arguments[0]

    # extraemos nuestras variables y les asignamos un valor por defecto en
    # caso de no existir
    options = dict(self.options)
    svgt_vars = options.pop("vars") if "vars" in options else {}
    svgt_dpi = options.pop("dpi") if "dpi" in options else 72
    svgt_isd = options.pop("inkscape_dir") if "inkscape_dir" in options else ""
    svgt_lvae = options.pop("list_vars_and_exit") == None \
                if "list_vars_and_exit" in options else False

    # si tenemos seteado el flag list_vars_and_exit mostramos las variables
    # y salimos del programa
    if svgt_lvae:
        self._show_vars(uri)
        sys.exit(0)

    # por como esta diseñado figure hay que evitar que la propiedad align
    # le llege a su imagen interior.
    fig_align = options.pop("align") if "align" in options else None

    # pasamos a crear el archivo png
    png_path = self._render_svg(uri, svgt_isd, svgt_dpi, svgt_vars)

    # agremamos la uri del png a las opciones
    options["uri"] = png_path

    # creamos el nodo imagen
    image_node = nodes.image(self.block_text, **options)

    # el contenido de caption y legend viene todo mezclado
    # como un iterable llamado docutils.statemachine.StringList
    # hay que separarlo en dos partes para crear la figure.
    caption_content, legend_content = self._separate_content(self.content)

    # creamos el nodo caption procesando su contenido con
    # nested_parse
    caption_node = nodes.caption("\n".join(caption_content))
    self.state.nested_parse(caption_content, self.content_offset, caption_node)

    # creamos el nodo legend y procesamos su contenido
    legend_node = nodes.legend("\n".join(legend_content))
    self.state.nested_parse(legend_content, self.content_offset, legend_node)

    # restautamos la variable align para crear el nodo figure
    if fig_align != None:
        options["align"] = fig_align

    # creaamos el susodicho nodo figure pasandole sus hijos
    figure_node = nodes.figure(self.block_text, image_node,
                               caption_node, legend_node, **options)

    # retornamos una lista con el nodo resultante
    return [figure_node]

Explicando el método _render_svg

Este método utiliza otros dos, _resolve_render_name que sera explicado después y el método _call que debido a su extrema simplicidad se recomienda leer directamente la documentació del clase subprocess.Popen

CMD = "{isp} {svg} -z -e {png} -d {dpi}"

# donde:
#   - uri es la direccion donde esta el svg a renderizar
#   - svgt_isd es el lugar donde esta inkscape
#   - svgt_dpi son los dpi del png a renderizar
#   - svgt_vars es un diccionario que contiene los valores de las variables del svg
def _render_svg(self, uri, svgt_isd, svgt_dpi, svgt_vars):

    # abrimos el svg y lo cargamos en un Template
    with open(uri) as fp:
        svg_tplt = string.Template(fp.read())

    # reemplazamos las variables con sus valores
    svg_src = svg_tplt.safe_substitute(svgt_vars)

    # obtenemos paths donde guardar:
    #   - El svg con las variables reemplazadas (fname_svg)
    #   - El png resultante (fname_png)
    fname_svg, fname_png = self._resolve_render_name(uri)

    # guardamos el svg reemplazado en su lugar
    with open(fname_svg, "w") as fp:
        fp.write(svg_src)

    # Ponemos los parametros de ejecucion de inkscape
    cmd = CMD.format(isp=os.path.join(svgt_isd, "inkscape"),
                     svg=fname_svg,
                     png=fname_png,
                     dpi=svgt_dpi)

    # ejecutamos inkscape
    self._call(cmd)

    # retornamos la direccion del nuevo png
    return fname_png

El método _resolve_render_name

Este método a primera vista es inecesario, ya que podríamos generar archivos temporales eficientemente con el modulo _template, pero dado como trabaja sphinx esto no es posible de primera mano.

# uri es la direccioón del svg original
def _resolve_render_name(self, uri):

    # leemos el directorio temporal de la variable global _tempdir
    # que pudo haber sido modificada por sphinx o tomamos el dir temporal
    # del sistema operativo. Esto se debe a que sphinx corre en un sandbox
    # y todos los archivos deben estar en la misma carpeta donde se
    # encuentra el archivo de configuración conf.py
    tempdir = _tempdir if _tempdir != None else tempfile.gettempdir()

    # extraemos el nombre del archivo sin su extensión
    basename = os.path.basename(uri).rsplit(".", 1)[0]

    # agregamos al directorio temporal el nombre del archivo sin la
    # extensión
    render_name = os.path.join(tempdir, basename)

    # generamos un nuevo nombre para el archivo svg agregando un entero
    # al final para evitar coliciones
    idx = ""
    unique_svg = render_name + "{idx}" + ".svg"
    while os.path.exists(unique_svg.format(idx=idx)):
       idx = idx + 1 if isinstance(idx, int) else 1
    unique_svg = unique_svg.format(idx=idx)

    # lo mismo para el png
    idx = ""
    unique_png = render_name + "{idx}" + ".png"
    while os.path.exists(unique_png.format(idx=idx)):
       idx = idx + 1 if isinstance(idx, int) else 1
    unique_png = unique_png.format(idx=idx)

    # retornamos los dos valores
    return unique_svg, unique_png

El método _separate_content

Este es el último método que utiliza el método run y es lo último que necesitamos para hacer el trabajo de svgt

# recibe por parámetro un string list con todos los nodos de texto del
# contenido de svgt
def _separate_content(self, content):

    # primero creamos un nodo stringlist exclusivamente para el caption
    caption_cnt = StringList(parent=content.parent,
                           parent_offset=content.parent_offset)

    # ahora algo IMPORTANTE.. la leyenda va a ser el mismo nodo contenido
    # por que la otra alternativa es crear uno nuevo y borrar el viejo
    # por que TODO NODO TIENE QUE SER PROCESADO O ELIMINADO MANUALMENTE
    legend_cnt = content # all nodes need to be procesed

    # si tenemos contenido copiamos el primer elemento al caption y quitamos
    # ese elemento de la leyenda (que es lo mismo que el content)
    if content:
        caption_cnt.append(content[0], content.source(0), content.offset(0))
        content.pop(0)
    return caption_cnt, legend_cnt

Pensando en sphinx

Para que este bicho funcione en sphinx es necesario agregar a nivel de modulo una función setup que recibe un único parámetro que es la instancia de sphinx corriendo.

def setup(app):

    # toma el valor la referencia a la variable de módulo _tempdir
    global _tempdir

    # esta función reci be dos parámetros requeridos para usarse como
    # slot de la señal build-finished de sphinx y sirve para limpiar
    # el directorio temporal.
    #   - la aplicación que ejecuto la señal
    #   - la exception que genero el fin del procesamiento o None si
    #     finalizo normalmente.
    def reset(app, ex):
        if _tempdir != None and os.path.isdir(_tempdir):
            shutil.rmtree(_tempdir)
        if ex:
            raise ex

    # agregamos una configuracion mas a sphinx llamada tempdir y asignamos
    # como valor por defecto _temp
    app.add_config_value("tempdir", "_temp", "")

    # tomamos el valor de tempdir de la configuración
    _tempdir = app.config["tempdir"]

    # reiniciamos el directorio temporal
    reset(app, None)

    # lo volvemos a crear
    os.mkdir(_tempdir)

    # conectamos la señal build-finished con la función reset
    app.connect("build-finished", reset)

Si desean mas información lean la documentación del api de extensiones de sphinx

Y como se usa todo esto

Bueno con rst2pdf o bien lo tiran en la carpeta de extensiones, o en el path donde tienen su rst y luego ejecutan

$ rst2pdf archivo.rst -e svgt

También pueden instalarlo desde pypi con easy_install o pip con los comandos:

$ pip install docutils_ext

o

$ easy_install docutils_ext

En el caso de sphinx, tienen que agregar el path donde se encuentre a sys.path y luego agregarla a la lista de extensiones.

Y funciona?

Pueden ver el código completo al momento de la publicación de este artículo aca además de poder descargar la última versión estable en la pestañita de downloads.

Lo de aca abajo dice

.. svgt:: img/temp.svg
    :vars: {"name": "that's all folks", "url": "img/troll.png"}
troll


Syndicated 2012-03-02 02:01:58 from Lateral Opinion

Going out

When we were not married, Rosario and I lived very far from each other which meant that when we met, we stuck together for 24, or 36 hours. Our 3rd date lasted almost 3 days.

A few days ago, we decided to have one of those, even though we were with Tato for a part of it.

So, we went from home to the Museo Participativo de Ciencias, in Recoleta, a cool kids science museum, full of cool stuff.

First we went to Buenos Aires Design, place full of cool and very overpriced designer stuff. Bought two pens.

Since Georgina, a friend of ours who lives *very* far away from us works at the Centro Cultural Recoleta, we decided to kidnap her for a cup of coffee

IMAG0365

In the meantime, Tato acquired two balloons and started making inappropiate things with them:

IMAG0366

But that was just a moment. Then... I'm an elephant!!!!

IMAG0369

We entered the Centro Cultural Recoleta, which is a very cool place...

IMAG0370

Tato and us performed a bunch of experiments. He even got to play with a Vandergraaf generator!!!!

IMAG0373

Then we wandered the scary areas...

IMAG0374

When we got out, it was getting dark...

IMAG0375

And Tato discovered the sad truth about candied apples: they are crap...

IMAG0377

We left tato with his aunties Laura and Agustina and started the grownup part of the date. First, we saw Anonymous protesting scientology (and a trollface!)...

IMAG0378

We had a picada at a place called Babieca. Great mortadela! I saw an example of rampant capitalism...

IMAG0380

Then our bank heist was foiled by a teller not giving us the "small denomination, unmarked, not-sequential" bills we wanted...

IMAG0381

Turns out Rosario had never been to the Ateneo Grand Splendid, the prettiest bookstore I have ever seen. So we went there to see some books and get a soda or something...

IMAG0384

The roof is pretty special...

IMAG0383

This is a restored teather, and the bar is in the stage...

IMAG0389

And you can see the ancient lights board (luckily: disabled)...

IMAG0386

So, we walked on Corrientes avenue and saw this (and yes, you can fake 7 seconds of tango by following the steps, but it's very hard for the lady)...

IMAG0391

Then there was a guy, walking in an elephant's trunk thong, while his friends (who had shorn him and covered him in flour) whistled and shouted: a "despedida de soltero", ritual hazing for a guy getting married...

IMAG0392

He ended talking with a 7-foot-tall transvestite in red sequins. The transvestite shouting "you are a healthy boy!"...

IMAG0393

So, after a nice evening at a borrowed appartment, next morning we got Tato back!

IMAG0394

A hobbitsian 3-hour breakfast ensued...

IMAG0395 IMAG0396 IMAG0397

Then taxi, train home, and we got back almost exactly 26 hours after we left. Everyone had fun, and thanks to Agustina and Laura (or Laura and Agustina), because without the mellis, this would have been impossible.


Syndicated 2012-03-02 01:43:08 from Lateral Opinion

Comunismo Revolucionario en #pyar

Sorry, spanish-only post, because I am so not translating this.


Siempre en las listas de tecnología alguien te tira algo como el viejo "Cómo hacer preguntas inteligentes" y cosas así. Es útil porque, asombrosamente, hay muchos que no son capaces (o no les sale) de pedir ayuda de manera que permita que te ayuden.

Los demás no tienen idea de qué estás hablando. Entonces necesitás explicar desde cero. Si tirás un bodoque de código de 400 líneas y decís "no anda, arréglenlo", nadie se va a molestar siquiera en leerlo.

Todos están ayudando gratis. Tenés que recompensarlos de alguna manera, aunque sea haciéndoles sentir que el problema es interesante, o que están ayudando a alguien que lo aprecia y los escucha.

Tenés que darle pelota a lo que te dicen, si no, es frustrante. Si es frustante, y no te pagan, al carajo.

No podés pedir "hagan mi trabajo" o "hagan mi tarea" o "hagan este práctico". Eso lo tenés que hacer vos. Como mucho te va a ayudar alguien con alguna cosa que te trabes, como te ayudaría tu profesor/compañero de trabajo.

No tenés que enojarte si no obtenés lo que querés. Puede ser que sea porque es muy difícil y los demás tampoco lo saben, o porque justo está todo el mundo ocupado, o porque sos un hinchapelotas que nadie quiere ayudar. Casi seguro que no es que están todos cogiendo secretarias.

Sin más preámbulo, les presento a pablitoooooo*, el pythonista número 7, comunista revolucionario, recuperador de su plusvalía por el mecanismo de pedir prestada la de los demás. No se han cambiado los nombres porque nadie ahí es inocente ;-)


Nota: PABLO* y pythonista7 son la misma persona, ok?

[20:45:47] <PABLOOO> holasssssssssss
[20:46:06] <PABLOOO> gentes...tengo q presentar mañana este juego
[20:46:09] <PABLOOO> http://pastebin.lugmen.org.ar/7304
[20:46:11] <lalita> PABLOOO: [#3225] pastebin.lugmen.org.ar - El pastebin m&aacute;s r&aacute;pido del oeste argentino.
[20:46:25] <PABLOOO> no va ni pa tras ni pa adelantre
[20:46:37] <PABLOOO> me podran dar una mano....plizzzzzzzzzz
[20:52:56] <PABLOOO> holasssssssss
[20:53:03] <PABLOOO> hay alguien????
[20:53:53] <alecu> PABLOOO, hola
[20:54:06] <PABLOOO> holasss...como va???
[20:54:12] <alecu> PABLOOO, lo lamento, pero mi religión no me permite hacer la tarea de otra gente
[20:54:22] <PABLOOO> nuuuuuuuu
[20:54:30] <PABLOOO> y si cambias de religion???
[20:54:52] <alecu> PABLOOO, y si cambiás la actitud? :-)
[20:55:04] <alecu> PABLOOO, si preguntás por cosas específicas, seguro que te dan bola
[20:55:04] <PABLOOO> ...no pego 1...
[20:55:27] <PABLOOO> lo puse aca a las 3 o 4 de la tarde...me digeron una par de cosas
[20:55:33] <PABLOOO> no saque nada
[20:55:43] <alecu> PABLOOO, empezá chiquito. Es decir, andá arreglando de a una cosa por vez.
[20:57:24] <PABLOOO> tengo ese while de...... no deja cargar al otro while...no toma datos...le mando print y la variable...y no sale nada
[20:57:47] <alecu> PABLOOO, aha.
[20:57:47] <PABLOOO> alguna sugerencia...
[20:57:49] <alecu> PABLOOO,  No entendí nada de lo que dijiste recién.
[20:57:59] <PABLOOO> el while...
[20:58:26] <alecu> PABLOOO, hay 13 whiles en tu código
[20:58:27] <PABLOOO> me quede ahi...tengo un juego ...tengo q ponerle vidas y tiempo...pongo el while
[20:58:58] <alecu> PABLOOO, en que curso tenés que entregarlo?
[20:59:22] <PABLOOO> fundamentos de programacion unaj
[20:59:35] <alecu> PABLOOO, en que universidad o carrera?
[20:59:43] <PABLOOO> sacamelo y me acuerdo de vos con mi profe
[20:59:47] <PABLOOO> XDDDDDD
[21:00:16] <alecu> PABLOOO, si yo fuera tu profe no podría aprobarte. :-)
[21:00:34] <ralsina> PABLOOO: decí una cosa sola que no anda, lo mas clara que puedas, y capaz que te podemos ayudar un poco
[21:00:37] <PABLOOO> naaaaaaaaaa....pero tengo la intencionnn
[21:00:44] <ralsina> PABLOOO: pero no podes esperar que te hagan los trabajos prácticos
[21:01:01] <PABLOOO> pero mañana es la final...o fui
[21:02:02] <PABLOOO> el problema es la def reglas...juego corria bien
[21:02:47] <ralsina> PABLOOO: esa funcion tiene casi 200 líneas.
[21:02:53] <PABLOOO> en def reglas...yo quiero meterle la opcion de q me carge difernetes cantidades de juegos y tiempos para realizarlas
[21:03:18] <PABLOOO> dame 1 minuto y lo pienso bien
[21:03:19] <ralsina> PABLOOO: no tengo idea ni de que juego se supone que es. Tenes que tratar de achicar el problema.
[21:03:32] <PABLOOO> ok...toy en eso
[21:04:12] <alecu> ok, me llaman a cenar...
[21:04:20] <alecu> PABLOOO, después contanos a la lista como te fue.
[21:04:45] <PABLOOO> okassssss
[21:05:47] <rbistolfi> PABLOOO: trata de identificar bien el problema, no sabemos que esperas que haga la funcion, ni que hace en lugar de lo que vos esperas
[21:18:52] <rbistolfi> Hau yottabit
[21:25:35] <rbistolfi> PABLOOO: che, esta dificil de leer ese codigo :[
[21:25:53] <PABLOOO> jajajajajaja....yo soy asi
[21:26:11] <rbistolfi> igual fijate que "fin" esta definido afuera de la funcion como global
[21:26:24] <rbistolfi> y despues la definis denuvo, pero en el scope local de la funcion
[21:26:29] <PABLOOO> creo q lo complique mucho...y esto en la recta final...del final final
[21:26:41] <rbistolfi> entendes la diferencia entre local y global?
[21:26:56] <PABLOOO> ....
[21:27:00] <rbistolfi> tambien fijate que los loops tienen que tener una condicion de salida clara
[21:27:41] <rbistolfi> no encuentro donde "f" se utiliza luego para salir del loop
[21:27:52] <rbistolfi> o no entiendo lo que queres hacer :)
[21:27:56] <PABLOOO> me anote para algoritmo...y no se q ...capaz q en un par de meses te sigo la conversacion
[21:28:04] <PABLOOO> por q hoy...
[21:29:14] <rbistolfi> PABLOOO: en la linea 181
[21:29:39] <PABLOOO> pera
[21:29:42] <rbistolfi> vos decis que vas a iterar hasta que f sea True
[21:30:38] <rbistolfi> bueno, me parece que f nunca se convierte en True
[21:30:38] <rbistolfi> despues usas "fin"
[21:30:38] <rbistolfi> asi que me parece te confundiste con "f" y "fin"
[21:32:26] <rbistolfi> yottabit: so, cuando venis a Argentina?
[21:34:14] <PABLOOO> f con fin
[21:34:18] <PABLOOO> toy en eso
[21:53:31] <pythonista7> lo podes terminar,es un trabajo muy important y lo teng q presentar mañana
[21:53:50] <rbistolfi> pythonista7: ?
[21:56:30] <pythonista7> http://pastebin.lugmen.org.ar/7304
[21:56:31] <lalita> [#3225] http://pastebin.lugmen.org.ar/7304 : pastebin.lugmen.org.ar - El pastebin m&aacute;s r&aacute;pido del oeste argentino. [by PABLOOO, 2012-02-29, 23:46:15]
[21:56:39] <yottabit> *toser*
[21:56:54] <pythonista7> este es el ejercicio,en realidad un jueguito simple
[21:57:46] <rbistolfi> yottabit: ya somos dos :P
[21:58:45] <pythonista7> ponganse media pila,lo sacan asi nomas o no???
[21:58:59] <rbistolfi> pythonista7: no
[21:59:02] <rbistolfi> sorry
[22:00:30] <rbistolfi> no creo que tengas suerte aca, pidiendo que te hagan la tarea
[22:01:31] <rbistolfi> mira
[22:02:11] <pythonista7> y no
[22:02:14] <pythonista7> creo q no
[22:02:21] <pythonista7> si se rascan a cuatro manos
[22:02:44] <pythonista7> o estan cogiendo con alguna secretaria.....:P
[22:02:58] <rbistolfi> si es tan importante, porque no estudias y lo haces bien
[22:04:00] <pythonista7> lo estudie,y lo se,solo kier una opinion
[22:04:06] <pythonista7> pero se ve q es al pedo
[22:04:21] <rbistolfi> ya te dije unas cosas que estaban mal
[22:04:33] <rbistolfi> lo del "fin" y "f"
[22:04:36] <pythonista7> x gent como esta el pais esta asi,cero solidaridad.......argentina tenia q ser
[22:04:38] <rbistolfi> lo arreglaste?
[22:04:48] <pythonista7> deja q busco x otro lado
[22:05:01] <pythonista7> no hay drama,fuck!!!
[22:05:05] <rbistolfi> gracias
[22:06:00] <rbistolfi> le estoy contando a la Vane sobre este pibe, y no me cree
[22:06:05] <TiN> juaz cero solidaridad xD
[22:10:49] <gatox> ahhh  bue

1 hora mas tarde...

[23:36:19] <PABLOOO> holasssssssssssss
[23:36:24] <PABLOOO> yo otra vezzzzzzzzz
[23:36:31] <PABLOOO> hay alguien?????
[23:39:09] <PABLOOO> holasssssssssssss
[23:39:17] <PABLOOO> queda alguien...
[23:39:23] <PABLOOO> todos durmiendo
[23:39:27] <PABLOOO> zzzzzzzzzzz
[23:43:47] <-- PABLOOO (ba8695e7@gateway/web/freenode/ip.186.134.149.231) has quit (Quit: Page closed)
[23:44:25] --> PABLOOO (ba8695e7@gateway/web/freenode/ip.186.134.149.231) has joined #pyar
[23:44:35] <PABLOOO> holaaaaaaaaaaassssssss
[23:44:46] <PABLOOO> hay alguien????
[23:46:47] <PABLOOO> holassssssss


Syndicated 2012-03-01 14:52:20 from Lateral Opinion

PyQt Quickie: command line parsing

So, you are writing a PyQt app, and you want it to support command line arguments. So you do something like this:

opt_parser = OptionParser()
opt_parser.add_option("-q", dest="quickly", action="store_true",
    help="Do it quickly (default=False)")
(options, args) = opt_parser.parse_args(sys.argv)
app = QApplication(sys.argv)
:
:
:

Or maybe even QApplication([]). Ok, you are doing it wrong. And this is wrong in most tutorials, too. Why? Because Qt (and thus PyQt) supports a bunch of useful command line options already. So if you do it like in the first listing, and pass "-style=oxygen" or whatever, one of the following will happen.

  1. OptParser is going to tell you it's not a valid option and abort
  2. You will ignore the option and not do anything useful with it
  3. You will have your own -style option and do two things with it

All three outcomes are less than ideal.

The right way to do this is:

opt_parser = OptionParser()
opt_parser.add_option("-q", dest="quickly", action="store_true",
    help="Do it quickly (default=False)")
app = QApplication(sys.argv)
(options, args) = opt_parser.parse_args(app.arguments())
:
:
:

This way, you give PyQt a chance to process the options it recognizes, and, then, you get to handle the rest, because app.arguments() has all Qt options removed.

The bad side of this is, you will make --help slightly slower, since it will have to build a QApplication to do nothing, and you will have undocumented options. Solution for both problems left as an exercise.


Syndicated 2012-02-24 02:38:39 from Lateral Opinion

The Lowly Symbols

Two nights ago, I was at a birthday party. In it, someone (name preserved because you don't know the guy) said something like "symbols are useful to rally people for a fight".

I answered "if I ever need to rally people to a fight, I would make sure to choose some uncool symbol (maybe a naked mole rat, rampant), so I at least know they are there because they understand the issue, and not because of cool marketing". Which is probably a pretty stupid thing to say, but:

  1. I was on my 3rd fernet
  2. I was trolling the other guy
  3. Fernet troll is drunk
  4. I kinda believe it

It's stupid because only accepting the help of true believers and not actively trying to make people believe are good ways to ensure you have a very motivated tiny minority on your side (Linux Year of The Desktop analogy ges here).

But I kinda believe it anyway, because being ugly and loved is warmer than being pretty and loved, because being difficult and appreciated is more valuable than being accessible and liked. But that only works if you are truly difficult, and not intentionally so, that's just being a poseur. And truly ugly, not Charlize-Theron-on-fat-makeup ugly.

So, to what point is any of us honestly annoying? That, friends, is the issue here. And if I ever have to lead others into something, I hope I do it as myself, and they come because of a reason that is theirs and not mine.

I am not here to convince people. I am here to know people.


Syndicated 2012-02-20 18:18:49 from Lateral Opinion

493 older entries...

New Advogato Features

New HTML Parser: The long-awaited libxml2 based HTML parser code is live. It needs further work but already handles most markup better than the original parser.

Keep up with the latest Advogato features by reading the Advogato status blog.

If you're a C programmer with some spare time, take a look at the mod_virgule project page and help us with one of the tasks on the ToDo list!