Attachment 'graphviz_0.1.py'

Download

   1 # -*- coding: iso-8859-1 -*-
   2 """
   3     MoinMoin - Graphviz Parser
   4     Based loosely on GNUPLOT parser by MoinMoin:KwonChanYoung
   5 
   6     @copyright: 2008 Wayne Tucker
   7     @license: GNU GPL, see COPYING for details.
   8 """
   9 
  10 """
  11     BASIC USAGE:
  12 
  13     embed a visualization of a graph in a wiki page:
  14 
  15 {{{#!graphviz
  16 digraph G {
  17     A -> B;
  18 };
  19 }}}
  20 
  21     ADVANCED USAGE:
  22 
  23     This parser will check the first lines of the Graphviz data for C++ style
  24     comments instructing it to use a different filter (dot, neato, twopi,
  25     circo, or fdp - see http://graphviz.org/ for more info), use a different
  26     format for the output (see the FORMATS list in the Parser class below),
  27     or to generate and pass a client-side image map.
  28 
  29     Options:
  30       filter - the filter to use (see Parser.FILTERS)
  31       format - the output format (see Parser.FORMATS)
  32       cmapx - the map name to use for the client-side image map.  Must match
  33               the graph name in the graph definition and shouldn't conflict
  34               with any other graphs that are used on the same page.
  35 
  36     embed a visualization of a graph in a wiki page, using the dot filter and
  37     providing a client-side image map (the filter=dot and format=png options are
  38     redundant since those are the defaults for this parser):
  39 
  40 {{{#!graphviz
  41 //filter=dot
  42 //format=png
  43 //cmapx=DocumentationMap
  44 digraph DocumentationMap {
  45     FrontPage [href="FrontPage", root=true];
  46     HelpOnEditing [href="HelpOnEditing"];
  47     SyntaxReference [href="SyntaxReference"];
  48     WikiSandBox [href="WikiSandBox", color="grey"];
  49     MoinMoin [href="http://moinmo.in"];
  50     FrontPage -> WikiSandBox;
  51     FrontPage -> MoinMoin;
  52     WikiSandBox -> HelpOnEditing;
  53     WikiSandBox -> SyntaxReference;
  54     SyntaxReference -> FrontPage;
  55 };
  56 }}}
  57 
  58 
  59     KNOWN BUGS:
  60       - Hasn't been thoroughly checked for potential methods of injecting
  61         arbitrary HTML into the output.
  62       - Only compatible with HTML rendering
  63       - May not use all of the MoinMoin interfaces properly - this is a
  64         quick hack based on looking at an example and digging through the
  65         MoinMoin source.  The MoinMoin development docs haven't been
  66         consulted (yet).
  67       - Only image formats (png and gif) are currently implemented
  68       - Comments must start at the beginning of the graphviz block, and at the
  69         beginning of their respective lines.  They must also not contain
  70         any extra whitespace surrounding the = sign.
  71 
  72 """
  73 
  74 # Change this to the directory that the Graphviz binaries (dot, neato, etc.)
  75 # are installed in.
  76 
  77 BINARY_PATH = '/usr/bin'
  78 
  79 import os
  80 import sys
  81 import base64
  82 import string
  83 import exceptions
  84 import codecs
  85 import subprocess
  86 import time
  87 import sha
  88 
  89 from MoinMoin import config
  90 from MoinMoin.action import AttachFile
  91 from MoinMoin import log
  92 from MoinMoin import wikiutil
  93 
  94 logging = log.getLogger(__name__)
  95 
  96 class GraphVizError(exceptions.RuntimeError):
  97     pass
  98 
  99 
 100 Dependencies = []
 101 
 102 class Parser:
 103     """Uses the Graphviz programs to create a visualization of a graph."""
 104 
 105     FILTERS = ['dot', 'neato', 'twopi', 'circo', 'fdp']
 106     IMAGE_FORMATS = ['png', 'gif']
 107     FORMATS = IMAGE_FORMATS + ['ps', 'svg', 'svgz', 'fig', 'mif', \
 108                                'hpgl', 'pcl', 'dia', 'imap', 'cmapx']
 109     extensions = []
 110     Dependencies = Dependencies
 111 
 112     def __init__(self, raw, request, **kw):
 113         self.raw = raw
 114         self.request = request
 115 
 116     def format(self, formatter):
 117         """ Send the text. """
 118         self.request.flush() # to identify error text
 119 
 120         self.filter = Parser.FILTERS[0]
 121         self.format = 'png'
 122         self.cmapx = None
 123 
 124         raw_lines = self.raw.splitlines()
 125         for l in raw_lines:
 126             if not l[0:2] == '//':
 127                 break
 128             if l.lower().startswith('//filter='):
 129                 tmp = l.split('=', 1)[1].lower()
 130                 if tmp in Parser.FILTERS:
 131                     self.filter = tmp
 132                 else:
 133                     logging.warn('unknown filter %s' % tmp)
 134             elif l.lower().startswith('//format='):
 135                 tmp = l.split('=', 1)[1]
 136                 if tmp in Parser.FORMATS:
 137                     self.format = tmp
 138             elif l.lower().startswith('//cmapx='):
 139                 self.cmapx = wikiutil.escape(l.split('=', 1)[1])
 140 
 141         if not self.format in Parser.IMAGE_FORMATS:
 142             raise NotImplementedError, "only formats %s are currently supported" % Parser.IMAGE_FORMATS
 143 
 144         if self.cmapx:
 145             if not self.format in Parser.IMAGE_FORMATS:
 146                 logging.warn('format %s is incompatible with cmapx option' % self.format)
 147                 self.cmapx = None
 148 
 149         img_name = 'graphviz_%s.%s' % (sha.new(self.raw).hexdigest(), self.format)
 150 
 151         self.pagename = formatter.page.page_name
 152         url = AttachFile.getAttachUrl(self.pagename, img_name, self.request)
 153         self.attach_dir=AttachFile.getAttachDir(self.request,self.pagename,create=1)
 154 
 155         self.delete_old_graphs(formatter)
 156 
 157         if not os.path.isfile(self.attach_dir + '/' + img_name):
 158             self.graphviz(self.raw, fn='%s/%s' % (self.attach_dir, img_name))
 159 
 160         if self.format in Parser.IMAGE_FORMATS:
 161             if self.cmapx:
 162                 self.request.write('\n' + self.graphviz(self.raw, format='cmapx') + '\n')
 163                 self.request.write(formatter.image(src="%s" % url, usemap="#%s" % self.cmapx))
 164             else:
 165                 self.request.write(formatter.image(src="%s" % url, alt="graphviz image"))
 166         else:
 167             # TODO: read the docs and figure out how to do this correctly
 168             self.request.write(formatter.attachment_link(True, url=url))
 169 
 170     def delete_old_graphs(self, formatter):
 171         page_info = formatter.page.lastEditInfo()
 172         try:
 173             page_date = page_info['time']
 174         except exceptions.KeyError, ex:
 175             return
 176         attach_files = AttachFile._get_files(self.request, self.pagename)
 177         for chart in attach_files:
 178             if chart.find('graphviz_') == 0 and chart[chart.rfind('.')+1:] in Parser.FORMATS:
 179                 fullpath = os.path.join(self.attach_dir, chart).encode(config.charset)
 180                 st = os.stat(fullpath)
 181                 chart_date =  self.request.user.getFormattedDateTime(st.st_mtime)
 182                 if chart_date < page_date :
 183                     os.remove(fullpath)
 184             else :
 185                 continue
 186 
 187     def graphviz(self, graph_def, fn=None, format=None):
 188         if not format:
 189             format = self.format
 190         if fn:
 191             p = subprocess.Popen(['%s/%s' % (BINARY_PATH, self.filter), '-T%s' % format, '-o', fn], shell=False, \
 192                                  stdin=subprocess.PIPE, \
 193                                  stderr=subprocess.PIPE)
 194         else:
 195             p = subprocess.Popen(['%s/%s' % (BINARY_PATH, self.filter), '-T%s' % format], shell=False, \
 196                                  stdin=subprocess.PIPE, \
 197                                  stdout=subprocess.PIPE, \
 198                                  stderr=subprocess.PIPE)
 199 
 200         p.stdin.write(graph_def)
 201         p.stdin.flush()
 202         p.stdin.close()
 203 
 204         p.wait()
 205 
 206         if not fn:
 207             output = p.stdout.read()
 208 
 209         errors = p.stderr.read()
 210         if len(errors) > 0:
 211             raise GraphVizError, errors
 212 
 213         p = None
 214 
 215         if fn:
 216             return None
 217         else:
 218             return output

Attached Files

To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.
  • [get | view] (2012-03-06 23:47:57, 11.2 KB) [[attachment:GraphvizParser-0.2.1.tar.bz2]]
  • [get | view] (2012-03-22 22:10:56, 11.5 KB) [[attachment:GraphvizParser-0.2.2.tar.bz2]]
  • [get | view] (2012-04-18 22:49:01, 11.5 KB) [[attachment:GraphvizParser-0.2.3.tar.bz2]]
  • [get | view] (2012-01-14 20:05:02, 11.1 KB) [[attachment:GraphvizParser-0.2.tar.bz2]]
  • [get | view] (2012-03-05 18:03:40, 2.2 KB) [[attachment:graphviz-encoding.patch]]
  • [get | view] (2008-11-01 19:09:07, 7.3 KB) [[attachment:graphviz_0.1.py]]
  • [get | view] (2011-09-19 22:05:44, 3.1 KB) [[attachment:patch-svg.diff]]
 All files | Selected Files: delete move to page copy to page

You are not allowed to attach a file to this page.