Hi,
I needed to document which blocks are available in a jinja2 template that I
am providing to my users, so I have created the attached script which takes
a jinja template and outputs a SVG file which shows which blocks are inside
which blocks. I am then converting the SVG file to PNG and PDF with Batik
and include them in my Sphinx-documentation.

I thought this could maybe be interesting for some of you, so here is the
script. Also attached is the output from running this on Sphinx' layout.html
template from the basic theme.

Martin

-- 
You received this message because you are subscribed to the Google Groups 
"sphinx-dev" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/sphinx-dev?hl=en.

#!/usr/bin/env python-2.5.1


#from lxml import etree    
import xml.etree.cElementTree as etree
import optparse
import re
import os.path
import sys

startblock_endblock_re=re.compile(r'\{%\-? (?P<tag>(block|endblock)) +(?P<name>\S*) *\-?%\}')

colors=range(10, 255, 32)

def color_of_level(level):
    col=colors[level]
    return 'rgb(%d,%d,%d)' % (col,col,col)

def main():
    parser=optparse.OptionParser(add_help_option=False)
    parser.add_option('--help',                  action='store_true', help='print help text', default=False)    
    parser.add_option('-t', '--template',        action='store',      help='jinja template to document')
    parser.add_option('-o', '--output',          action='store',      help='SVG file to write')
    parser.add_option('-w', '--min-width',       action='store',      help='Minimal width, default: %default', type='float', default=30)
    parser.add_option('-h', '--min-height',      action='store',      help='Minimal height, default: %default', type='float', default=30)
    parser.add_option('-x', '--x-padding',       action='store',      help='Horizontal padding between boxes, default: %default', type='float', default=20)
    parser.add_option('-y', '--y-padding',       action='store',      help='Vertical padding between boxes, default: %default', type='float', default=10)
    parser.add_option('-f', '--first-y-padding', action='store',      help='Vertical padding between a box and its first child, default: %default', type='float', default=27)
    parser.add_option('-l', '--label-y-offset',  action='store',      help='Vertical padding between a box and its label, default: %default', type='float', default=20)
    parser.add_option('-c', '--char-width',      action='store',      help='Amount of space allocated for one char of text, default: %default', type='float', default=8.0)    

    opt,arg=parser.parse_args()

    if opt.help:
        parser.print_help()
        return

    if opt.template is None:
        parser.error('No input template given')

    JinjaBlock.opt=opt


    file=JinjaBlock(os.path.basename(opt.template))
    stack=[file]
    for mo in startblock_endblock_re.finditer(open(opt.template).read()):
        if mo.group('tag')=='block':
            block=JinjaBlock(mo.group('name'))
            stack[-1].add_child(block)
            stack.append(block)
        else:
            stack.pop()

    # construct the SVG document
    root = etree.Element('svg', version="1.1", xmlns="http://www.w3.org/2000/svg";)
    width,height=file.draw(root, x=0, y=0)
    root.attrib['width']=str(width+2)
    root.attrib['height']=str(height+2)    

    # output the file
    if opt.output is None:
        outfile=sys.stdout
    else:
        outfile=open(opt.output, 'w')

    #outfile.write(etree.tostring(root, pretty_print=True, xml_declaration=True, encoding="UTF-8"))
    outfile.write(etree.tostring(root, encoding="UTF-8"))
        



class JinjaBlock(object):

    opt=None

    x_padding=20    
    y_padding=10
    first_y_padding=30    

    def __init__(self, name):
        self.name=name
        self.children=[]

    def add_child(self, child):
        self.children.append(child)

    def draw(self, canvas, x, y, depth=0):

        width=self.opt.char_width*len(self.name) + 2.0*self.opt.x_padding
        width=max(self.opt.min_width,width)
        height=0
        first=True
        for child in self.children:
            if first:
                y_padding=self.opt.first_y_padding
                first=False
            else:
                y_padding=self.opt.y_padding

            height+=y_padding
                
            child_width, child_height = child.draw(canvas, x=x+self.opt.x_padding, y=y+height, depth=depth+1)

            width=max(width, child_width+2*self.opt.x_padding)
            height+=child_height

        height+=self.opt.y_padding

        height=max(height, self.opt.min_height)

        etree.SubElement(canvas, 'rect',
                         x=str(x), y=str(y),
                         rx="10", ry="10",
                         width=str(width), height=str(height),
                         style="fill:%s;stroke-width:1;stroke:rgb(154,33,235);fill-opacity:0.1" % color_of_level(depth))

        text=etree.SubElement(canvas, 'text',
                              x=str(x+0.5*self.opt.x_padding),
                              y=str(y+self.opt.label_y_offset),
                              style="font-family:Verdana")
        text.text=self.name


        return width, height


if __name__=='__main__':
    main()

<<attachment: layout.svg>>

Attachment: layout.pdf
Description: Adobe PDF document

Reply via email to