lunes, julio 31, 2017

Renderizar Markdown en Python: Las extensiones

Lo que hace interesante al módulo de Markdown en Python es la incorporación de un API que permite añadir extensiones y adaptarlo a las necesidades específicas. Existe todo un conjunto de extensiones oficiales, aquellas que son soportadas por los autores del módulo markdown y un buen conjunto de extensiones de terceros que pueden servir para añadir el comportamiento que nos interese al sistema.

Por ejemplo, si se quiere usar alguna de los añadidos a markdown de github, se puede hacer con la extensión py-gfm:

$ virtualenv markdown
$ cd markdown
$ source bin/activate
$ # Se instala markdown automáticamente
$ pip install py-gfm

Para renderizar ficheros que use esta extensión, se puede usar el siguiente código:

import markdown
from mdx_gfm import GithubFlavoredMarkdownExtension
import sys

md = markdown.Markdown(extensions=[GithubFlavoredMarkdownExtension()])
for filename in sys.argv[1:]:
    with open(filename, mode="r") as f:
        content = f.read()
        html = md.convert(content.decode('utf-8'))
        print html.encode('utf-8')

Al igual que ocurre con el módulo normal, desde la propia línea de comandos es posible indicar que se cargue una extensión, para el ejemplo anterior:

python  g-m markdown -x mdx_gfm file1 file2 ...

La opción -x especifica el path hasta el módulo donde se encuentra la extensión.

Existe documentación para crear una extensión y añadirla al sistema de markdown. No es demasiado complicado desarrollar una extensión, aunque desde mi punto de vista la documentación no es del todo clara. Un ejemplo de extensión, que añade a todas las etiquetas una clase parrafo sería el siguiente código. Dejo para otra entrada mis notas de como desarrollar nuevas extensiones.

from markdown.util import etree
from markdown.treeprocessors import Treeprocessor
from markdown.extensions import Extension

class ParagraphProcessor(Treeprocessor):
    def __init__(self, md):
        super(ParagraphProcessor, self).__init__(md)
    def set_paragraph_style(self, element):
        for child in element:
            if child.tag == "p":
                child.set("class", "parrafo") #set the class attribute
            self.set_paragraph_style(child)
    def run(self, root):
        self.set_paragraph_style(root)

class ParagraphClassExtension(Extension):
     def extendMarkdown(self, md, md_globals):
         md.treeprocessors.add('paragraphProcessor', ParagraphProcessor(md),">inline")

Si suponemos que el código anterior está en un módulo llamado pproc y que está en nuestro PYTHONPATH se puede usar con:

import markdown
from mdx_gfm import GithubFlavoredMarkdownExtension
from pproc import ParagraphClassExtension
import sys

md = markdown.Markdown(extensions=[GithubFlavoredMarkdownExtension(), ParagraphClassExtension()])
for filename in sys.argv[1:]:
    with open(filename, mode="r") as f:
        content = f.read()
        html = md.convert(content.decode('utf-8'))
        print html.encode('utf-8')

No hay comentarios: