├── .gitignore ├── README.md ├── examples ├── configs.py ├── example.py └── test.md └── mdx_graphviz.py /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.pyc 3 | *.html 4 | *.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### Python-Markdown-Graphviz 2 | 3 | The goal of this library is to support embedding graphviz graphs inside 4 | Markdown documents. 5 | 6 | Requires: 7 | 8 | * Python (tested on 2.5, 2.6, not sure about 2.4 off hand) 9 | * Graphviz 10 | * ubuntu: ``apt-get install graphviz`` 11 | * others: download at [graphviz.org](graphviz.org) 12 | * Python-Markdown 13 | * ``easy_install Markdown`` 14 | 15 | Read the ``examples/example.py`` for a simple example. 16 | 17 | Some overview is available [in this blog post][blog]. 18 | 19 | [blog]: http://lethain.com/entry/2010/jan/16/a-python-markdown-extension-for-embedding-graphviz/ "A Python Markdown Extension for Embedding Graphviz" 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /examples/configs.py: -------------------------------------------------------------------------------- 1 | import markdown 2 | 3 | fin = open("test.md", 'r') 4 | txt = fin.read() 5 | fin.close() 6 | md = markdown.Markdown( 7 | extensions=['graphviz'], 8 | extension_configs={'graphviz': 9 | {'FORMAT':'gif'} 10 | }, 11 | ) 12 | print md.convert(txt) 13 | -------------------------------------------------------------------------------- /examples/example.py: -------------------------------------------------------------------------------- 1 | import markdown 2 | 3 | fin = open("test.md", 'r') 4 | txt = fin.read() 5 | fin.close() 6 | md = markdown.Markdown(extensions=['graphviz']) 7 | print md.convert(txt) 8 | -------------------------------------------------------------------------------- /examples/test.md: -------------------------------------------------------------------------------- 1 | # Test 2 | 3 | 4 | digraph a { 5 | a -> b; 6 | } 7 | 8 | 9 | * a 10 | * b 11 | * c 12 | 13 | 14 | -------------------------------------------------------------------------------- /mdx_graphviz.py: -------------------------------------------------------------------------------- 1 | """ 2 | ### Markdown-Python-Graphviz 3 | 4 | This module is an extention to [Python-Markdown][pymd] which makes it 5 | possible to embed [Graphviz][gv] syntax into Markdown documents. 6 | 7 | ### Requirements 8 | 9 | Using this module requires: 10 | * Python-Markdown 11 | * Graphviz (particularly ``dot``) 12 | 13 | ### Syntax 14 | 15 | Wrap Graphviz definitions within a dot/neato/dotty/lefty tag. 16 | 17 | An example document: 18 | 19 | This is some text above a graph. 20 | 21 | 22 | digraph a { 23 | nodesep=1.0; 24 | rankdir=LR; 25 | a -> b -> c ->d; 26 | } 27 | 28 | 29 | Some other text between two graphs. 30 | 31 | 32 | some graph in neato... 33 | 34 | 35 | This is also some text below a graph. 36 | 37 | Note that the opening and closing tags should come at the beginning of 38 | their lines and should be immediately followed by a newline. 39 | 40 | ### Usage 41 | 42 | import markdown 43 | md = markdown.Markdown( 44 | extensions=['graphviz'], 45 | extension_configs={'graphviz' : {'DOT','/usr/bin/dot'}} 46 | ) 47 | return md.convert(some_text) 48 | 49 | 50 | [pymd]: http://www.freewisdom.org/projects/python-markdown/ "Python-Markdown" 51 | [gv]: http://www.graphviz.org/ "Graphviz" 52 | 53 | """ 54 | import markdown, re, markdown.preprocessors, subprocess 55 | 56 | class GraphvizExtension(markdown.Extension): 57 | def __init__(self, configs): 58 | self.config = {'FORMAT':'png', 'BINARY_PATH':"", 'WRITE_IMGS_DIR':"", "BASE_IMG_LINK_DIR":""} 59 | for key, value in configs: 60 | self.config[key] = value 61 | 62 | def reset(self): 63 | pass 64 | 65 | def extendMarkdown(self, md, md_globals): 66 | "Add GraphvizExtension to the Markdown instance." 67 | md.registerExtension(self) 68 | self.parser = md.parser 69 | md.preprocessors.add('graphviz', GraphvizPreprocessor(self), '_begin') 70 | 71 | class GraphvizPreprocessor(markdown.preprocessors.Preprocessor): 72 | "Find all graphviz blocks, generate images and inject image link to generated images." 73 | 74 | def __init__ (self, graphviz): 75 | self.graphviz = graphviz 76 | self.formatters = ["dot", "neato", "lefty", "dotty"] 77 | 78 | def run(self, lines): 79 | start_tags = [ "<%s>" % x for x in self.formatters ] 80 | end_tags = [ "" % x for x in self.formatters ] 81 | graph_n = 0 82 | new_lines = [] 83 | block = [] 84 | in_block = None 85 | for line in lines: 86 | if line in start_tags: 87 | assert(block == []) 88 | in_block = self.extract_format(line) 89 | elif line in end_tags: 90 | new_lines.append(self.graph(graph_n, in_block, block)) 91 | graph_n = graph_n + 1 92 | block = [] 93 | in_block = None 94 | elif in_block in self.formatters: 95 | block.append(line) 96 | else: 97 | new_lines.append(line) 98 | assert(block == []) 99 | return new_lines 100 | 101 | def extract_format(self, tag): 102 | format = tag[1:-1] 103 | assert(format in self.formatters) 104 | return format 105 | 106 | def graph(self, n, type, lines): 107 | "Generates a graph from lines and returns a string containing n image link to created graph." 108 | assert(type in self.formatters) 109 | cmd = "%s%s -T%s" % (self.graphviz.config["BINARY_PATH"], 110 | type, 111 | self.graphviz.config["FORMAT"]) 112 | p = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, close_fds=True) 113 | #(child_stdin, child_stdout) = (p.stdin, p.stdout) 114 | p.stdin.write("\n".join(lines)) 115 | p.stdin.close() 116 | p.wait() 117 | filepath = "%s%s.%s" % (self.graphviz.config["WRITE_IMGS_DIR"], n, self.graphviz.config["FORMAT"]) 118 | fout = open(filepath, 'w') 119 | fout.write(p.stdout.read()) 120 | fout.close() 121 | output_path = "%s%s.%s" % (self.graphviz.config["BASE_IMG_LINK_DIR"], n, self.graphviz.config["FORMAT"]) 122 | return "![Graphviz chart %s](%s)" % (n, output_path) 123 | 124 | def makeExtension(configs=None) : 125 | return GraphvizExtension(configs=configs) 126 | --------------------------------------------------------------------------------