Per subject. This is my first attempt at a Sphinx extension, so I'm 
certain there's plenty of room for improvement; see attached.

Usage is as follows:

.. graphviz::
  strict digraph {
    foo -> bar -> baz;
    foo -> qux;
  }


This in rendered into PNG (for use with HTML), PDF (for use with LaTeX) 
and postscript.

Please let me know if there are improvements I could make which would 
allow this extension to be merged into Sphinx proper. Thanks!

--~--~---------~--~----~------------~-------~--~----~
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
-~----------~----~----~----~------~----~------~--~---

# -*- coding: utf-8 -*-
"""
    sphinx.ext.graphviz
    ~~~~~~~~~~~~~~~~~~

    Allow graphviz-formatted graphs to be included in Sphinx-generated
    documentation inline.

    :copyright: 2008 Dell MessageOne, Inc.
    :license: BSD.
"""

import os
import sys
from subprocess import Popen, PIPE
try:
    from hashlib import sha
except ImportError:
    from sha import sha

from docutils import nodes
from docutils.parsers.rst import directives

_output_formats = {
#   'image/svg+xml': 'svg',
    'image/png': 'png',
    'application/postscript': 'ps',
}

class graphviz(nodes.General, nodes.Element):
    pass

def process_graphviz_nodes(app, doctree, docname):
    for node in doctree.traverse(graphviz):
        try:
            content = '\n'.join(node['graphviz_content'])
            filename = '%s' % sha(content).hexdigest()
            outfn = os.path.join(app.builder.outdir, '_images', 'graphviz', filename)
            if not os.path.exists(os.path.dirname(outfn)):
                os.makedirs(os.path.dirname(outfn))
            # iterate over the above-listed types
            for format_mime, format_ext in _output_formats.iteritems():
                graphviz_process = Popen([
                    getattr(app.builder.config, 'graphviz_dot', 'dot'),
                    '-T%s' % (format_ext,),
                    '-o', '%s.%s' % (outfn, format_ext), 
                ], stdin=PIPE)
                graphviz_process.stdin.write(content)
                graphviz_process.stdin.close()
                graphviz_process.wait()
                relfn = '_images/graphviz/%s' % (filename,)
            newnode = nodes.image()
            newnode['candidates'] = dict( [ (format_mime, '%s.%s' % (relfn, format_ext)) for (format_mime, format_ext) in _output_formats.iteritems() ] )
            # build PDF output from the previously generated postscript
            Popen([
                getattr(app.builder.config, 'graphviz_ps2pdf', 'ps2pdf'),
                '%s.ps' % (outfn,),
                '%s.pdf' % (outfn,)
            ]).wait()
            newnode['candidates']['application/pdf'] = '%s.pdf' % (outfn,)
            # and that's all, folks!
            node.replace_self(newnode)
        except Exception, err:
            from traceback import format_exception_only
            msg = ''.join(format_exception_only(err.__class__, err))
            newnode = doctree.reporter.error('Exception occured evaluating '
                                             'graphviz expression: \n%s' %
                                             msg, base_node=node)
            node.replace_self(newnode)

def graphviz_directive(name, arguments, options, content, lineno,
                    content_offset, block_txt, state, state_machine):
    node = graphviz()
    node['graphviz_content'] = content
    return [node]

def setup(app):
    app.add_node(graphviz)
    app.add_directive('graphviz', graphviz_directive, 1, (0, 0, 0))
    app.add_config_value('graphviz_dot', 'dot', False)
    app.add_config_value('graphviz_ps2pdf', 'ps2pdf', False)
    app.connect('doctree-resolved', process_graphviz_nodes)

# vim: sw=4 ts=4 sts=4 ai et

Reply via email to