From 734ecea56a1c2d4dfb1b15d9060caba65f87507b Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Thu, 30 Sep 2010 13:38:22 -0400 Subject: [PATCH] Migrated my depgraph page from my unversioned homepage to this blog. --- local.css | 5 ++++ posts/depgraph.mdwn | 47 ++++++++++++++++++++++++++++++++++++ posts/depgraph/depgraph.png | Bin 0 -> 227093 bytes 3 files changed, 52 insertions(+) create mode 100644 posts/depgraph.mdwn create mode 100644 posts/depgraph/depgraph.png diff --git a/local.css b/local.css index 718f25f..0d6b349 100644 --- a/local.css +++ b/local.css @@ -16,6 +16,11 @@ body { background: #e7e7e7; } .actions ul { border: none; padding-bottom: 0px; font-family: sans-serif;} #footer { border: none; font-family: sans-serif;} +.scaled { + width: 100%; + height: auto; +} + .sidebar { border: solid; border-width: 1px; diff --git a/posts/depgraph.mdwn b/posts/depgraph.mdwn new file mode 100644 index 0000000..098a88c --- /dev/null +++ b/posts/depgraph.mdwn @@ -0,0 +1,47 @@ +This set of scripts scans a Python file for module dependencies, and +generates code for [Graphviz dot][graphviz]. + +Originally by Toby Dickenson. Good for giving you the "long view" on +how your project is organized. I've [altered][] the [originals][] a +bit. + +My `py2depgraph` also prints out path information for each module, so +that you can show or hide module nodes based on those paths. For +example, ignoring system modules to focus on your additions. + +My `depgraph2dot` has an added method +`depgraph2dot.invalidpath(module_name, path)` that you can override to +determine the paths you like. + +I've also added the `depgraph2dot` methods + +* `is_Cext(module_name, path)`, +* `Cext_depends(module_name, path)`, +* `Cext_edge_attributes(module_name, Cext_name)`, +* `Cext_node_attributes(Cext_name)`, and +* `Cext_depcolor(Cext_name)` + +to detect and configure the shared C libraries extending Python, so +you know where to look for the code your Python depends on. + +As example, here is the depgraph of my protein unfolding program [unfold.py][] + + $ python py2depgraph.py unfold.py | python depgraph2dot.py | dot -T png -o depgraph.png + +with standard python modules in orange, +python packages in hash-based colors, +and C extension modules in light blue. +Again, these are only the files containing either `wking` or `comedi` +in their paths. + +[[!img depgraph.png class="scaled" + alt="unfold.py dependency graph" + title="unfold.py dependency graph"]] + +[graphviz]: http://www.graphviz.org +[altered]: http://www.physics.drexel.edu/~wking/code/git/git.php?p=depgraph.git +[originals]: http://tarind.com/depgraph.html +[unfold.py]: http://www.physics.drexel.edu/~wking/code/git/git.php?p=unfold_protein.git + +[[!tag tags/tools]] +[[!tag tags/programming]] diff --git a/posts/depgraph/depgraph.png b/posts/depgraph/depgraph.png new file mode 100644 index 0000000000000000000000000000000000000000..7f2c5af9fe0f8209ff67e84b40ebbfb4d90abcc1 GIT binary patch literal 227093 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�#xLmH&?QSQKQ!O%WIgyb6ksK88YwB-rRPN+0mCPoQQofHTF!3q2G&j`T1L zmzdToKYsK@2!=EE!O@ZMOKMDj^J?FsHs|7|2~38M0l>h;LJS)aML)(_5>mtdu)hH; zi#r};41OQLswB`KJn|Jr$op(;=D71y`h$Qof+CVP{!`!3a79Y$IEINfV>U7DX|zBy z6??Uz)sOqvfDI|ZGl-ZT5;H_*GBDwFn(YbzmV^M3ler8taRs&l+WD83BeJBSB4cT8 zF4-SYha?Vcn>sw0>~OR;1u_U!xJy_@ckkV+1Vw_u^xj0T%s(cQ+5HNHenh{A34 zusEZi0PY5w7=2MBrso;NVI{^Z3*vMkS(iV1@&oVz0K*dlJrFLEhEC8L0FO{>aB4gi z3nPlAT3>|R;B@wkjXg?qljx;%@sIGsd0(9CafFJzB=1Sg&VVLJCj`tE=X1@iuiVu* zSODP?}v&cUI$#ZQcpfqe8w=xY$R ze-VQWvYH4_g!aG!noCgb3dR}?Vxw*z9+2#Zl7kH7JZvOcRt!_j$Z7+4dJNr}qF`-b zEpli;fGU|#(s4V%E{DHbCCxgh(}Sx<^mDEiIxdv(DCN#%HOsu?ZZG8@$54| z^(tfm)0ITGM%czb-ID12SWvEY07}59K>K$Fwdg9=F1P(_b$o-agv`uFjMc;okC#z} z%?J@&%>@tcI21GxNiRVqKw${4%LatDA-X7hD>V~<)e6*I!g2yzR1wTfc~6dbR-kf& zc+t@MI?eSy@F6fPAVjLYd&yM>hV5xVExX0GqFC<*7?yx7ML6SsS}eB`WK}!~3R2EL z^A{DqT_GbGXAIUNdhA4XRU@)v2%`p06PW>c9|V3}1BnB0Qntveg&@Uz1Cj>2oLyt4A@Btm{x&=NN8zAK~6-(_26UhDfzHD6$R5$Zv6WeSLEaj zFiingaYJ{l_@B=d5}X@&hHYueQlqYM8{n7+m)e9cs|I&6l;bctv0)Q?0rkVIzn7a#^OIiI&uAeSWS!^DD7}b z(?B0X(j(ANA%1TVMGMvW37hiZsxz$?j%l1O`q<_KM8KI?7xO>>+*vIeFgITa zmy0!>rKD;Q6&2Oo*~!esHRYJsFf=kUgCop0JUs2HAf7vI4O)w>J9k#$nPMY}EPg+Z z@)YFFxI(=8Kz+&ZL-;`)q(s0*yb8Iw@gVJS9Ot0@1R;=Or7159G}u)K=v5scn9(nV z{OI5q5fOpj0}LyPzJf4LQi3M&JNg44ROD#E_;dk{f1o$R^;S$Eb_>&t5XGnn){5S@ z)>m{h$%UBbCgACy{xKpE#Vo>Bz!VV@GMAhMV|5u)F#=n+Ldur{qXR)L38IBX34vZ1 zhDsKCsiL)50zeeY(2UzH{$>ThdqG0N1)^kkG^Ye6f&L5nw7eF1F*;Iv-3g32kHi(D z_B2}HUx{$(Xcj*V18_|c7tl4>#9W2=UG3}2=x7H)krDP%I`WJk8lH`adQgyM>3s$c z9sO4l;37$h1qsR9;eTxae?exSo#J*)9#PV(ufr{XqYdE{N%XypEv(NCClM?O=u8dZ z;CT4ES)%CSf&#Yi4#HDG;YSb`;2&7(i2r^BXcMb!FF~9jk%uT5+Ulz~PbuVC16PkZ z*_uH0M37+u*}&@rjV@Zxiy);(4dXVz69F022b^MO&|Nq#U&qtM%6wZ`m