Skip to content

Instantly share code, notes, and snippets.

@esle
Created February 20, 2012 06:08
Show Gist options
  • Save esle/1868078 to your computer and use it in GitHub Desktop.
Save esle/1868078 to your computer and use it in GitHub Desktop.
dot directive for reStructuredText, with this you can write ..dot:: things
"""
dot directive (require graphviz)
"""
from docutils import nodes
from docutils.parsers.rst import directives, Directive
import subprocess as sp
nthUnnamed = 0
class Dot(Directive):
required_arguments = 0
optional_arguments = 1
has_content = True
final_argument_whitespace = True
'''dot image generator'''
def run(self):
self.assert_has_content()
global nthUnnamed
try:
filename = self.arguments[0]
except:
filename = ('dot%d.png' % nthUnnamed)
nthUnnamed += 1
content = '\n'.join(self.content)
filetype = filename[filename.rfind('.')+1:]
args = ['dot', '-o'+filename, '-T'+filetype]
dot = sp.Popen(args, 0, None, sp.PIPE)
dot.stdin.write( content )
dot.stdin.close()
ret = dot.wait()
if ret:
return [nodes.error('some error occured')]
else:
return [nodes.raw('', '<img src="%s" alt="%s"/>'%(filename, filename), format='html')]
@dasbh
Copy link

dasbh commented Nov 27, 2014

Slight modification to use inline images thus avoiding files created on disk.

"""
dot directive (require graphviz)
"""

import base64
from docutils import nodes
from docutils.parsers.rst import directives, Directive

import subprocess as sp

nthUnnamed = 0
class Dot(Directive):
    required_arguments = 0
    optional_arguments = 1
    has_content = True
    final_argument_whitespace = True

    '''dot image generator'''
    def run(self):
        self.assert_has_content()
        global nthUnnamed
        try:
            filename = self.arguments[0]
        except:
            filename = ('dot%d.png' % nthUnnamed)
            nthUnnamed += 1
        content = '\n'.join(self.content)

        return self.render(content, filename)

    def render(self, content, filename):
        filetype = filename[filename.rfind('.')+1:]
        args = ['dot', '-T'+filetype]
        try:
                dot = sp.Popen(args, stdin=sp.PIPE, stderr=sp.PIPE,stdout=sp.PIPE)
                dot.stdin.write( content )
                dot.stdin.close()

                output = ''
                while True:
                    b = dot.stdout.read()
                    if b :
                        output = output + str(b)
                    else :
                        break

                err = ''
                while True:
                    b= dot.stderr.readline()
                    if not b :
                        break
                    err = err + b

                ret = dot.wait()

                encoded = base64.b64encode(output)

                html = '<img src="data:image/%s;base64,%s" >' % (filetype, encoded)

        except Exception as e:
                err = str(e ) + ' : ' +  str(args)

        if html:
                return [nodes.raw('', html, format='html')]
        else:
                return [nodes.raw('', '<p>Error : ' + err + '</p><pre>' + content + '</pre>', format='html')]

@simon-gunacker
Copy link

Nice work. Any idea how I can make this run for pdf files?

@gbuzogany
Copy link

gbuzogany commented Jan 14, 2019

For python3 (so you can use with OmniMarkup for example):

"""
dot directive (require graphviz)
"""

import base64
from docutils import nodes
from docutils.parsers.rst import directives, Directive

import subprocess as sp

nthUnnamed = 0
class Dot(Directive):
    required_arguments = 0
    optional_arguments = 1
    has_content = True
    final_argument_whitespace = True

    '''dot image generator'''
    def run(self):
        self.assert_has_content()
        global nthUnnamed
        try:
            filename = self.arguments[0]
        except:
            filename = ('dot%d.png' % nthUnnamed)
            nthUnnamed += 1
        content = '\n'.join(self.content)

        return self.render(content, filename)

    def render(self, content, filename):
        filetype = filename[filename.rfind('.')+1:]
        args = ['dot', '-T'+filetype]
        html = None

        dot = sp.Popen(args, stdin=sp.PIPE, stderr=sp.PIPE,stdout=sp.PIPE)
        output = dot.communicate( content.encode('utf-8'))

        encoded = base64.b64encode(output[0]).decode('utf-8')

        html = '<img src="data:image/%s;base64,%s" >' % (filetype, encoded)

        if html:
                return [nodes.raw('', html, format='html')]
        else:
                return [nodes.raw('', '<p>Error : ' + err + '</p><pre>' + content + '</pre>', format='html')]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment