1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
| | From ac1bd55d07fd1bad2f4a92dc0809607c407d9140 Mon Sep 17 00:00:00 2001
From: "Maciej A. Czyzewski" <maciejanthonyczyzewski@gmail.com>
Date: Wed, 9 Jun 2021 15:29:18 +0200
Subject: [PATCH] feature: new params for graphviz + solves #70
- solve abs path bug #70
- new params for graphviz (ranksep; layout)
- tested layout `dot`; `fdp` (square graph)
- updated `.gitignore` (files gen. after `visualize_pyan_architecture.sh`)
---
.gitignore | 5 ++++
README.md | 6 ++--
pyan/main.py | 55 +++++++++++++++++++++++++++++++---
visualize_pyan_architecture.sh | 5 ++++
4 files changed, 64 insertions(+), 7 deletions(-)
diff --git a/.gitignore b/.gitignore
index 990fdc0c..93313aaf 100644
--- a/.gitignore
+++ b/.gitignore
@@ -162,3 +162,8 @@ htmlcov
.idea/
.history/
.vscode/
+
+# our vis. of architecture
+architecture.dot
+architecture.html
+architecture.svg
diff --git a/README.md b/README.md
index d1f19dcf..9e6919a3 100644
--- a/README.md
+++ b/README.md
@@ -48,7 +48,7 @@ See `pyan3 --help`.
Example:
-`pyan *.py --uses --no-defines --colored --grouped --annotated --dot >myuses.dot`
+`pyan3 *.py --uses --no-defines --colored --grouped --annotated --dot >myuses.dot`
Then render using your favorite GraphViz filter, mainly `dot` or `fdp`:
@@ -56,11 +56,11 @@ Then render using your favorite GraphViz filter, mainly `dot` or `fdp`:
Or use directly
-`pyan *.py --uses --no-defines --colored --grouped --annotated --svg >myuses.svg`
+`pyan3 *.py --uses --no-defines --colored --grouped --annotated --svg >myuses.svg`
You can also export as an interactive HTML
-`pyan *.py --uses --no-defines --colored --grouped --annotated --html > myuses.html`
+`pyan3 *.py --uses --no-defines --colored --grouped --annotated --html > myuses.html`
Alternatively, you can call `pyan` from a script
diff --git a/pyan/main.py b/pyan/main.py
index 5d079714..b1a16f63 100644
--- a/pyan/main.py
+++ b/pyan/main.py
@@ -141,6 +141,31 @@ def main(cli_args=None):
),
)
+ parser.add_argument(
+ "--dot-ranksep",
+ default="0.5",
+ dest="ranksep",
+ help=(
+ "specifies the dot graph 'ranksep' property for "
+ "controlling desired rank separation, in inches. "
+ "Allowed values: [0.02 .. 1000.0]. "
+ "[dot only]"
+ ),
+ )
+
+ parser.add_argument(
+ "--graphviz-layout",
+ default="dot",
+ dest="layout",
+ help=(
+ "specifies the graphviz 'layout' property for "
+ "the name of the layout algorithm to use. "
+ "Allowed values: ['dot', 'neato', 'fdp', 'sfdp', 'twopi', 'circo']. "
+ "Recommended values: ['dot', 'fdp']. "
+ "[graphviz only]"
+ ),
+ )
+
parser.add_argument(
"-a",
"--annotated",
@@ -159,7 +184,12 @@ def main(cli_args=None):
known_args, unknown_args = parser.parse_known_args(cli_args)
- filenames = [fn2 for fn in unknown_args for fn2 in glob(fn, recursive=True)]
+
+ filenames = []
+ for fn in unknown_args:
+ for fn2 in glob(fn, recursive=True):
+ abs_fn2 = os.path.abspath(fn2)
+ filenames.append(abs_fn2)
# determine root
if known_args.root is not None:
@@ -203,6 +233,11 @@ def main(cli_args=None):
handler = logging.FileHandler(known_args.logname)
logger.addHandler(handler)
+ logger.debug(f"[files] {unknown_args}")
+
+ if root:
+ root = os.path.abspath(root)
+
v = CallGraphVisitor(filenames, logger=logger, root=root)
if known_args.function or known_args.namespace:
@@ -222,13 +257,25 @@ def main(cli_args=None):
writer = None
if known_args.dot:
- writer = DotWriter(graph, options=["rankdir=" + known_args.rankdir], output=known_args.filename, logger=logger)
+ writer = DotWriter(graph, options=[
+ "rankdir=" + known_args.rankdir,
+ "ranksep=" + known_args.ranksep,
+ "layout=" + known_args.layout,
+ ], output=known_args.filename, logger=logger)
if known_args.html:
- writer = HTMLWriter(graph, options=["rankdir=" + known_args.rankdir], output=known_args.filename, logger=logger)
+ writer = HTMLWriter(graph, options=[
+ "rankdir=" + known_args.rankdir,
+ "ranksep=" + known_args.ranksep,
+ "layout=" + known_args.layout,
+ ], output=known_args.filename, logger=logger)
if known_args.svg:
- writer = SVGWriter(graph, options=["rankdir=" + known_args.rankdir], output=known_args.filename, logger=logger)
+ writer = SVGWriter(graph, options=[
+ "rankdir=" + known_args.rankdir,
+ "ranksep=" + known_args.ranksep,
+ "layout=" + known_args.layout,
+ ], output=known_args.filename, logger=logger)
if known_args.tgf:
writer = TgfWriter(graph, output=known_args.filename, logger=logger)
diff --git a/visualize_pyan_architecture.sh b/visualize_pyan_architecture.sh
index 22c63342..81b6ca24 100755
--- a/visualize_pyan_architecture.sh
+++ b/visualize_pyan_architecture.sh
@@ -2,3 +2,8 @@
echo -ne "Pyan architecture: generating architecture.{dot,svg}\n"
python3 -m pyan pyan/*.py --no-defines --uses --colored --annotate --dot -V >architecture.dot 2>architecture.log
dot -Tsvg architecture.dot >architecture.svg
+echo -ne "Pyan architecture: generating architecture.{html,graphviz=fdp}\n"
+python3 -m pyan pyan/*.py --no-defines --uses \
+ --grouped --nested-groups \
+ --graphviz-layout fdp \
+ --colored --html > architecture.html
|