import sys, os, tempfile, atexit import BaseHTTPServer, SimpleHTTPServer, htmlentitydefs from cStringIO import StringIO from dottest import DotBuilder class HtmlDotBuilder(DotBuilder): def __init__(self, root): DotBuilder.__init__(self) self.root = root def addnode(self, obj, **kwds): if obj is not None and obj is not self.root: try: tag = DotHTTPRequestHandler.ById[id(obj)] except KeyError: tag = str(len(DotHTTPRequestHandler.ById)) DotHTTPRequestHandler.ById[id(obj)] = tag DotHTTPRequestHandler.Content[tag] = DotFile(obj) kwds['URL'] = '/%s/page.html' % tag return DotBuilder.addnode(self, obj, **kwds) class DotFile: def __init__(self, obj): self.obj = obj self.dotfile = None def getfile(self): if self.dotfile is None: dot = HtmlDotBuilder(self.obj) dot.buildnode(self.obj, `self.obj`[:100], reclimit=3) self.dotfile = tempfile.mktemp('.dot') DotHTTPRequestHandler.ClearFiles.append(self.dotfile) g = open(self.dotfile, 'w') dot.dump(g) g.close() return self.dotfile def getimg(self): f = os.popen('dot -Tgif "%s"' % self.getfile(), 'r') return f, "image/gif" def getpage(self): f = StringIO() print >> f, '' print >> f, '' print >> f, repr(self.obj)[:255] print >> f, '' print >> f, '' print >> f, '' print >> f, '' g = os.popen('dot -Tcmap "%s"' % self.getfile(), 'r') f.write(g.read()) g.close() print >> f, '' print >> f, '' print >> f, '' f.seek(0) return f, "text/html" class DotHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): Content = {} ById = {} ClearFiles = [] def send_head(self): """Common code for GET and HEAD commands. This sends the response code and MIME headers. Return value is either a file object (which has to be copied to the outputfile by the caller unless the command was HEAD, and must be closed by the caller under all circumstances), or None, in which case the caller has nothing further to do. """ k = self.path.split('/') assert not k[0] try: f, contenttype = StringIO('not found: %r' % k), 'text/plain' if len(k) > 2 and k[1] in self.Content: dotfile = self.Content[k[1]] if k[2] == 'page.html': f, contenttype = dotfile.getpage() elif k[2] == 'graph.gif': f, contenttype = dotfile.getimg() except: import traceback f = StringIO() print >> f, '-'*40 traceback.print_exc(file=f) print >> f, '-'*40 print f.getvalue() f.seek(0) contenttype = "text/plain" self.send_response(200) self.send_header("Content-type", contenttype) self.end_headers() return f def address_string(self): """Override to return the client address with no formatting.""" return "%s:%d" % self.client_address bkgnd_thread_running = False def show(obj): global bkgnd_thread_running import os, thread if not bkgnd_thread_running: server_address = ('', 8000) httpd = BaseHTTPServer.HTTPServer(server_address, DotHTTPRequestHandler) thread.start_new_thread(httpd.serve_forever, ()) bkgnd_thread_running = True DotHTTPRequestHandler.Content = {'0': DotFile(obj)} DotHTTPRequestHandler.ById = {id(obj): '0'} # XXX try different browsers (e.g. mozilla) try: os.system('galeon http://127.0.0.1:8000/0/page.html') finally: DotHTTPRequestHandler.Content = {} DotHTTPRequestHandler.ById = {} clearfiles = DotHTTPRequestHandler.ClearFiles DotHTTPRequestHandler.ClearFiles = [] for filename in clearfiles: try: os.unlink(filename) except OSError: pass # # Text-to-HTML character conversion # TEXT_TO_HTML = { } for c in range(256): TEXT_TO_HTML[chr(c)] = chr(c) for entity, character in htmlentitydefs.entitydefs.items(): TEXT_TO_HTML[character] = "&" + entity + ";" TEXT_TO_HTML_NBSP = TEXT_TO_HTML.copy() TEXT_TO_HTML_NBSP[" "] = " " def text2html(text): return "".join(map(TEXT_TO_HTML.get, text)) def text2html_nbsp(text): return "".join(map(TEXT_TO_HTML_NBSP.get, text)) if __name__ == '__main__': # test import compiler, sys from httpdot import show p = compiler.parse(open('zz.py').read()) show(p)