ATLAS Offline Software
Loading...
Searching...
No Matches
defects_dump_graph.py
Go to the documentation of this file.
1#!/usr/bin/env python
2
3from os import makedirs
4from os.path import isdir
5from argparse import ArgumentParser
6from typing import Mapping, Union, TextIO
7
8from DQDefects import DefectsDB
9from DQDefects.virtual_logic import DefectLogic
10
11DEPENDSON_DIR = "dependson"
12
13class Node(object):
14 def __init__(self, name: str):
15 self.name = name
16 self.children = set()
17 self.parents = set()
18
19 def get_name(self) -> str:
20 return self.name
21
22 @property
23 def virtual(self) -> bool:
24 return bool(self.children)
25
26 @property
27 def primary(self) -> bool:
28 return not self.virtual
29
30 @property
31 def has_primary_children(self) -> bool:
32 return any(c.primary for c in self.children)
33
34 @property
35 def only_primary_children(self) -> bool:
36 return all(c.primary for c in self.children)
37
38 def __repr__(self):
39 return (f'<Node {self.name} parents="{[n.name for n in self.parents]}" '
40 f'children="{[n.name for n in self.children]}">')
41
42 def dot(self, current_node=False, tooltip: str ="", viewing_dependents: bool =False) -> str:
43 import html
44 color = "grey" if self.primary else "white"
45 if current_node:
46 color = "darkslategray2" if viewing_dependents else "gold"
47
48 tooltip = ("[Virtual]" if self.virtual else "[Primary]") + " " + html.escape(tooltip, True)
49 label = self.name
50
51
52 if current_node:
53 # Clicking on the current node toggles between views
54 if viewing_dependents:
55 url = f"../{self.name}.svg"
56 label += r"\n[Deep dependants]"
57 else:
58 url = f"{DEPENDSON_DIR}/{self.name}.svg"
59 label += r"\n[Dependencies]"
60 else:
61 url = "%s.svg" % self.name
62
63 return f'{self.name} [fillcolor={color}, style=filled, URL="{url}", tooltip="{tooltip}", label="{label}"];'
64
65def build_tree(all_logic: Mapping[str, DefectLogic]) -> dict[str, Node]:
66
67 all_nodes: dict[str, Node] = {}
68
69 def make_primary(current_logic: str) -> Node:
70 if current_logic in all_nodes:
71 return all_nodes[current_logic]
72 all_nodes[current_logic] = node = Node(current_logic)
73 return node
74
75 def explore_virtual(current_logic: str) -> Node:
76 if current_logic in all_nodes:
77 return all_nodes[current_logic]
78
79 this_logic = all_logic[current_logic]
80 all_nodes[current_logic] = node = Node(current_logic)
81
82 for name in this_logic.clauses:
83 if name in all_logic:
84 child = explore_virtual(name)
85 else:
86 child = make_primary(name)
87
88 child.parents.add(node)
89 node.children.add(child)
90
91 return node
92
93 for name in all_logic:
94 explore_virtual(name)
95
96 return all_nodes
97
98def walk(node: Node, visited: set[Node], visit_primary: bool, fd: TextIO):
99 visited.add(node)
100
101 for subnode in sorted(node.children, key=Node.get_name):
102 if subnode.virtual or (subnode.primary and visit_primary):
103 print(f"{node.name} -> {subnode.name}", file=fd)
104 walk(subnode, visited, visit_primary, fd)
105
106def dump_visited(fd: TextIO, current_node: Node, nodes: set[Node],
107 descs: Mapping[Union[str, int], str], parents: bool):
108 for node in sorted(nodes, key=Node.get_name):
109 at_current_node = node.name == current_node.name
110 description = descs.get(node.name, node.name)
111 # Line breaks in defect descriptions mess up the svg generation
112 description = description.replace('\n', ' ')
113 print(node.dot(at_current_node, description, parents), file=fd)
114
115def build_dependency_graph(output_dir: str, node: Node, descs: Mapping[Union[str, int], str]):
116
117 with open("%s/%s.dot" % (output_dir, node.name), "w") as fd:
118 print(f"strict digraph {node.name} {{", file=fd)
119 print("rankdir=LR;\n", file=fd)
120
121 visited = set()
122
123 for parent in sorted(node.parents, key=Node.get_name):
124 print(f"{parent.name} -> {node.name}", file=fd)
125 visited.add(parent)
126
127 walk(node, visited, node.has_primary_children, fd)
128
129 dump_visited(fd, node, visited, descs, parents=False)
130
131 print("}", file=fd)
132
133def build_parent_tree(output_dir: str, node: Node, descs: Mapping[Union[str, int], str]):
134
135 visited = set([node])
136
137 with open(f"{output_dir}/{DEPENDSON_DIR}/{node.name}.dot", "w") as fd:
138 def walk_parents(node):
139 visited.add(node)
140 for parent in node.parents:
141 print(f"{parent.name} -> {node.name}", file=fd)
142 walk_parents(parent)
143
144 print(f"strict digraph {node.name} {{", file=fd)
145 print("rankdir=LR;\n", file=fd)
146
147 walk_parents(node)
148
149 dump_visited(fd, node, visited, descs, parents=True)
150
151 print("}", file=fd)
152
153def render_all_flags(output_dir: str, all_nodes: dict[str, Node], descs: Mapping[Union[str, int], str]):
154
155 path = "%s/%s" % (output_dir, DEPENDSON_DIR)
156 if not isdir(path):
157 makedirs(path)
158
159 for _, node in sorted(all_nodes.items()):
160 build_dependency_graph(output_dir, node, descs)
161 build_parent_tree(output_dir, node, descs)
162
163def main():
164
165 parser = ArgumentParser(description="Dump defect viewer information")
166
167 parser.add_argument("-t", "--tag", default="HEAD", help="Defect tag")
168 parser.add_argument("-o", "--output", default=".", help="Directory to dump files")
169
170 args = parser.parse_args()
171
172 # Instantiate the Defect DB
173 db = DefectsDB(tag=args.tag)
174
175 descs = db.all_defect_descriptions
176
177 # Build node objects
178 all_nodes = build_tree(db.virtual_defect_logics)
179
180 # Write outputs
181 output_dir = "%s/%s" % (args.output, args.tag)
182 render_all_flags(output_dir, all_nodes, descs)
183
184if __name__ == "__main__":
185 main()
void print(char *figname, TCanvas *c1)
STL class.
walk(Node node, set[Node] visited, bool visit_primary, TextIO fd)
render_all_flags(str output_dir, dict[str, Node] all_nodes, Mapping[Union[str, int], str] descs)
dict[str, Node] build_tree(Mapping[str, DefectLogic] all_logic)
build_parent_tree(str output_dir, Node node, Mapping[Union[str, int], str] descs)
build_dependency_graph(str output_dir, Node node, Mapping[Union[str, int], str] descs)
dump_visited(TextIO fd, Node current_node, set[Node] nodes, Mapping[Union[str, int], str] descs, bool parents)
Definition dot.py:1