def _delayed_edge(key: str, progenitor: pydot.Dot, old_source: str, new_source: str) -> str: """Draw a specific edge between two nodes, modifying the old label if applicable. Args: key: The key associated with the edge. progenitor: The parent cluster. old_source: The edge source. new_source: The edge sync. Returns: The `new_source`. """ edge = progenitor.get_edge(old_source, new_source) if edge: edge = edge[0] label = f"{edge.get_label()}, {key}" edge.set_label(label) else: progenitor.add_edge( pydot.Edge(src=old_source, dst=new_source, label=f" {key}")) return new_source
class Grafo: def __init__(self, vertices, use_pydot=False): self.__verts__ = vertices self.__adjmx__ = [[] for i in range(vertices)] self.__arest__ = 0 if use_pydot: self.__graph__ = Dot(graph_type='graph') for i in range(vertices): self.__graph__.add_node(Node(str(i))) else: self.__graph__ = None def aresta(self, v1, v2): if v2 in self.__adjmx__[v1]: return False self.__adjmx__[v1].append(v2) self.__adjmx__[v2].append(v1) self.__arest__ = self.__arest__ + 1 if self.__graph__ is not None: self.__graph__.add_edge(Edge(str(v1), str(v2))) return True def aresta_aleat(self): done = False while not done: v1 = __random_gen__.randint(self.__verts__) v2 = v1 while v2 == v1: v2 = __random_gen__.randint(self.__verts__) done = self.aresta(v1, v2) def conecta(self, alfa): max_art = (self.__verts__ * (self.__verts__ - 1)) // 2 arestas = round(alfa * max_art) for _ in range(arestas): self.aresta_aleat() def show(self): if self.__graph__ is not None: from IPython.display import Image return Image(self.__graph__.create(format='png')) def contemC4(self): for v in range(self.__verts__): tem_caminho = [False] * self.__verts__ for w in self.__adjmx__[v]: for u in self.__adjmx__[w]: if u != v: if tem_caminho[u]: return v else: tem_caminho[u] = True return -1 def testeC4(self, vert): def mostra_C4(v): if self.__graph__ is not None: for i in range(len(v)): self.__graph__.get_node(str(v[i]))[0].set_style('filled') self.__graph__.get_edge(str(v[i]), str( v[(i + 1) % len(v)]))[0].set_style('bold') for v in self.__adjmx__[vert]: for w in self.__adjmx__[v]: if w != vert: for u in self.__adjmx__[w]: if u != vert and u != v: for z in self.__adjmx__[u]: if z == vert: mostra_C4([vert, v, w, u]) return True return False
def pkgTree(db, packageName): """Creates the call tree of internal package functions and procedures""" # Tries to import pydot module try: from pydot import find_graphviz, Dot, Edge, Node except ImportError: message = _("Function not available because pydot module is not installed.\n\t") message += _("Go to http://dkbza.org/pydot.html to get it.") raise PysqlException(message) # Reads conf conf = PysqlConf.getConfig() format = conf.get("graph_format") # Output format of the picture fontname = conf.get("graph_fontname") # Font used for functions names fontsize = conf.get("graph_fontsize") # Font size for functions names fontcolor = conf.get("graph_fontcolor") # Color of functions names # Gets picture generator prog = getProg(find_graphviz(), conf.get("graph_program"), "fdp") package = OraObject(objectName=packageName) package.guessInfos(db) graph = Dot(overlap="false", splines="true") # Lists of function or procedure verbs = [] # Tries to resolve synonym and describe the target #TODO: factorise this code!! if package.getType() == "SYNONYM": package = package.getTarget(db) if package.getType() == "SYNONYM": raise PysqlException(_("Too much synonym recursion")) if package.getType() not in ("PACKAGE", "PACKAGE BODY"): raise PysqlException(_("This is not a package or package not found")) # Gets package body content package.setType(u"PACKAGE BODY") print CYAN + _("Extracting package source...") + RESET content = package.getSQLAsList(db) # Removes comments print CYAN + _("Parsing source and building graph...") + RESET newContent = [] comment = False for line in content: line, comment = removeComment(line, comment) newContent.append(line) content = newContent # Gets procedures and functions for line in content: result = re.match("\s*(FUNCTION|PROCEDURE)\s+(.+?)[\s|\(]+", line, re.I) if result: verbs.append(re.escape(result.group(2))) graph.add_node(Node(result.group(2).upper(), shape="box", label=result.group(2).upper(), \ fontsize=str(fontsize), fontname=fontname, fontcolor=fontcolor)) if not verbs: raise PysqlException(_("This package does not have any readable function or procedure")) verbs = "|".join(verbs) # Gets call of functions/procedure inside each other currentVerb = "" for line in content: # Doesn't pay attention to end lines if re.match("\s*END.*;", line, re.I): continue # Marks the function/procedure we are parsing result = re.match("\s*(FUNCTION|PROCEDURE)\s+(.+?)[\s|\(]+", line, re.I) if result: currentVerb = result.group(2) continue # else we get a circular reference below ;-) result = re.match(".*\s(%s).*" % verbs, line, re.I) if result: if graph.get_edge(currentVerb.upper(), result.group(1).upper()) is None: graph.add_edge(Edge(src=currentVerb.upper(), dst=result.group(1).upper())) filename = package.getName() + "_dep." + format generateImage(graph, filename, prog, format) viewImage(filename)