From cbe993b71ea9f3b3fed1c15326869697640bab6d Mon Sep 17 00:00:00 2001 From: Bjorn Pettersen Date: Sun, 21 Apr 2024 03:53:38 +0200 Subject: [PATCH] A (more?) stable cycle graph, and default max-bacon to infinite when looking for cycles (might not be the best idea..?) --- pydeps/cli.py | 2 ++ pydeps/depgraph.py | 8 ++++---- pydeps/depgraph2dot.py | 16 +++++++++++----- pydeps/render_context.py | 13 ++++++++++--- 4 files changed, 27 insertions(+), 12 deletions(-) diff --git a/pydeps/cli.py b/pydeps/cli.py index 69a4e5d..7e283e2 100644 --- a/pydeps/cli.py +++ b/pydeps/cli.py @@ -192,6 +192,8 @@ def parse_args(argv=()): _args.show = not _args.no_show if _args.no_dot and _args.show_cycles: error("Can't use --no=dot and --show-cycles together") # pragma: nocover + if _args.show_cycles: + _args.max_bacon = 0 if _args.no_dot: _args.show_dot = False if _args.max_bacon == 0: diff --git a/pydeps/depgraph.py b/pydeps/depgraph.py index 932c398..3409131 100644 --- a/pydeps/depgraph.py +++ b/pydeps/depgraph.py @@ -372,12 +372,12 @@ def traverse(node, path): self.cyclerelations.add( (cycle[i], cycle[i + 1]) ) - return + # return - for impmod in node.imports: - traverse(self.sources[impmod], path + [node.name]) + for impmod in sorted(node.imports): + traverse(self.sources[impmod], list(path + [node.name])) - for src in list(self.sources.values()): + for src in sorted(self.sources.values(), key=lambda x: x.name.lower()): traverse(src, []) def connect_generations(self): diff --git a/pydeps/depgraph2dot.py b/pydeps/depgraph2dot.py index 33c1b71..beb9ed3 100644 --- a/pydeps/depgraph2dot.py +++ b/pydeps/depgraph2dot.py @@ -89,8 +89,9 @@ def render(self, depgraph, ctx): with ctx.graph(concentrate=False): visited = set() drawn = set() + relations = set() - for aname, bname in depgraph.cyclerelations: + for aname, bname in sorted(depgraph.cyclerelations): try: a = depgraph.sources[aname] b = depgraph.sources[bname] @@ -99,14 +100,19 @@ def render(self, depgraph, ctx): drawn.add((bname, aname)) ctx.write_rule( bname, aname, - weight=depgraph.proximity_metric(a, b), - minlen=depgraph.dissimilarity_metric(a, b), + # weight=depgraph.proximity_metric(a, b), + # minlen=depgraph.dissimilarity_metric(a, b), ) + relations.add(aname) + relations.add(bname) visited.add(a) visited.add(b) space = colors.ColorSpace(visited) - for src in visited: + for src in sorted(visited, key=lambda x: x.name.lower()): + # if src.name not in relations: + # print('skipping', src.name) + # continue bg, fg = depgraph.get_colors(src, space) kwargs = {} @@ -131,5 +137,5 @@ def dep2dot(target, depgraph, **kw): def cycles2dot(target, depgraph, **kw): dotter = CycleGraphDot(**kw) - ctx = RenderBuffer(target, **kw) + ctx = RenderBuffer(target, remove_islands=False, **kw) return dotter.render(depgraph, ctx) diff --git a/pydeps/render_context.py b/pydeps/render_context.py index 7272752..582e9ed 100644 --- a/pydeps/render_context.py +++ b/pydeps/render_context.py @@ -147,9 +147,11 @@ def __init__(self, target, min_cluster_size=0, max_cluster_size=1, keep_target_cluster=False, - collapse_target_cluster=False, **kw): + collapse_target_cluster=False, + remove_islands=False, **kw): self.target = target self.nodes = [] + self.rule_nodes = set() self.clusters = defaultdict(list) self.rules = {} self.reverse = reverse @@ -162,6 +164,7 @@ def __init__(self, target, self.graph_attrs = {} self.keep_target_cluster = keep_target_cluster self.collapse_target_cluster = collapse_target_cluster + self.remove_islands = remove_islands def _nodecolor(self, n): for node, attrs in self.nodes: @@ -254,11 +257,11 @@ def text(self): ctx.writeln('}') # non-clustered nodes - for n, attrs in self.nodes: + for n, attrs in sorted(self.nodes, key=lambda x: x[0].lower()): ctx.write_node(n, **attrs) intercluster = set() - for (a, b), attrs in sorted(self.rules.items()): + for (a, b), attrs in sorted(self.rules.items(), key=lambda x: (x[0][0].lower(), x[0][1].lower())): # sort by node name if a == b: continue cida = self._clusterid(a) @@ -308,6 +311,8 @@ def _clusterid(self, n): return n.split('.')[0] def write_node(self, n, **attrs): + if self.remove_islands and n not in self.rule_nodes: + return clusterid = self._clusterid(n) if self.cluster: self.clusters[clusterid].append((n, attrs)) @@ -315,6 +320,8 @@ def write_node(self, n, **attrs): self.nodes.append((n, attrs)) def write_rule(self, a, b, **attrs): + self.rule_nodes.add(a) + self.rule_nodes.add(b) self.rules[(a, b)] = attrs def _target_clusterid(self):