source: trunk/trac-hacks/masterticketsplugin/mastertickets/graphviz.py @ 448

Revision 448, 3.7 KB checked in by dgynn, 5 years ago (diff)

updating non-modified trac-hacks to  th:changeset:4267

Line 
1# -*- coding: utf-8 -*-
2# Created by Noah Kantrowitz on 2007-12-21.
3# Copyright (c) 2007 Noah Kantrowitz. All rights reserved.
4import os
5import subprocess
6import tempfile
7import time
8import itertools
9
10try:
11    set = set
12except NameError:
13    from sets import Set as set
14
15def _format_options(base_string, options):
16    return u'%s [%s]'%(base_string, u', '.join([u'%s="%s"'%x for x in options.iteritems()]))
17
18class Edge(dict):
19    """Model for an edge in a dot graph."""
20
21    def __init__(self, source, dest, **kwargs):
22        self.source = source
23        self.dest = dest
24        dict.__init__(self, **kwargs)
25
26    def __str__(self):
27        ret = u'%s -> %s'%(self.source.name, self.dest.name)
28        if self:
29            ret = _format_options(ret, self)
30        return ret
31
32    def __hash__(self):
33        return hash(id(self))
34
35
36class Node(dict):
37    """Model for a node in a dot graph."""
38
39    def __init__(self, name, **kwargs):
40        self.name = unicode(name)
41        self.edges = []
42        dict.__init__(self, **kwargs)
43
44    def __str__(self):
45        ret = self.name
46        if self:
47            ret = _format_options(ret, self)
48        return ret
49
50    def __gt__(self, other):
51        """Allow node1 > node2 to add an edge."""
52        edge = Edge(self, other)
53        self.edges.append(edge)
54        other.edges.append(edge)
55        return edge
56
57    def __lt__(self, other):
58        edge = Edge(other, self)
59        self.edges.append(edge)
60        other.edges.append(edge)
61        return edge
62
63    def __hash__(self):
64        return hash(id(self))
65
66
67class Graph(object):
68    """A model object for a graphviz digraph."""
69
70    def __init__(self, name=u'graph'):
71        super(Graph,self).__init__()
72        self.name = name
73        self.nodes = []
74        self._node_map = {}
75        self.edges = []
76
77    def add(self, obj):
78        if isinstance(obj, Node):
79            self.nodes.append(obj)
80            self._node_map[obj.name] = obj
81        elif isinstance(obj, Edge):
82            self.edges.append(obj)
83
84    def __getitem__(self, key):
85        key = unicode(key)
86        if key not in self._node_map:
87            new_node = Node(key)
88            self._node_map[key] = new_node
89            self.nodes.append(new_node)
90        return self._node_map[key]
91
92    def __delitem__(self, key):
93        key = unicode(key)
94        node = self._node_map.pop(key)
95        self.nodes.remove(node)
96
97    def __str__(self):
98        edges = []
99        nodes = []
100       
101        memo = set()
102        def process(lst):
103            for obj in lst:
104                if obj in memo:
105                    continue
106                memo.add(obj)
107               
108                if isinstance(obj, Node):
109                    nodes.append(obj)
110                    process(obj.edges)
111                elif isinstance(obj, Edge):
112                    edges.append(obj)
113                    if isinstance(obj.source, Node):
114                        process((obj.source,))
115                    if isinstance(obj.dest, Node):
116                        process((obj.dest,))
117       
118        process(self.nodes)
119        process(self.edges)
120       
121        lines = [u'digraph "%s" {'%self.name]
122        for obj in itertools.chain(nodes, edges):
123            lines.append(u'\t%s;'%obj)
124        lines.append(u'}')
125        return u'\n'.join(lines)
126
127    def render(self, dot_path='dot', format='png'):
128        """Render a dot graph."""
129        proc = subprocess.Popen([dot_path, '-T%s'%format], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
130        out, _ = proc.communicate(unicode(self).encode('utf8'))
131        return out
132
133
134if __name__ == '__main__':
135    g = Graph()
136    root = Node('me')
137    root > Node('them')
138    root < Node(u'Üs')
139   
140    g.add(root)
141   
142    print g.render()
Note: See TracBrowser for help on using the repository browser.