pydeps
Python module dependency visualization. This package installs the pydeps command, and normal usage will be to use it from the command line.
How to install
pip install pydeps
Basic Usage
From the shell:
shell> pydeps [flags] module-directory
Detailed usage examples can be found below the version history.
Creating the graph:
To create graphs you need to install Graphviz Please follow the installation instructions provided in the Graphviz link (and make sure the dot
command is on your path).
Displaying the graph:
To display the resulting .svg files, pydeps
by default calls firefox foo.svg
. This is can be overridden with the --display PROGRAM
option, where PROGRAM
is an executable that can display the image file of the graph.
Feature requests and bug reports:
Please report bugs and feature requests on GitHub at https://github.com/thebjorn/pydeps/issues
Version history
Version 1.9.0 supports Python 3.8.
Version 1.8.7 includes a new flag --rmprefix
which lets you remove prefixes from the node-labels in the graph. The name of the nodes are not effected so this does not cause merging of nodes, nor does it change coloring - but it can lead to multiple nodes with the same label (hovering over the node will give the full name). Thanks to aroberge for the enhancement request.
Version 1.8.5 With svg as the output format (which is the default), paths are now hilighted on mouse hover (thanks to tomasito665 for the enhancement request).
Version 1.8.2 incldes a new flag --only
that causes pydeps to only report on the paths specified:
shell> pydeps mypackage --only mypackage.a mypackage.b
Version 1.8.0 includes 4 new flags for drawing external dependencies as clusters. See below for examples. Additionally, the arrowheads now have the color of the source node.
Version 1.7.3 includes a new flag -xx
or --exclude-exact
which matches the functionality of the --exclude
flag, except it requires an exact match, i.e. -xx foo.bar
will exclude foo.bar, but not foo.bar.blob
(thanks to AvenzaOleg for the PR).
Version 1.7.2 includes a new flag, --no-output
, which prevents creation of the .svg/.png file.
Version 1.7.1 fixes excludes in .pydeps files (thanks to eqvis for the bug report).
Version 1.7.0 The new --reverse
flag reverses the direction of the arrows in the dependency graph, so they point to the imported module instead of from the imported module (thanks to goetzk for the bug report and tobiasmaier for the PR!).
Version 1.5.0 Python 3 support (thanks to eight04 for the PR).
Version 1.3.4 --externals
will now include modules that haven't been installed (what modulefinder
calls badmodules
).
Version 1.2.8 A shortcut for finding the direct external dependencies of a package was added:
pydeps --externals mypackage
which will print a json formatted list of module names to the screen, e.g.:
(dev) go|c:\srv\lib\dk-tasklib> pydeps --externals dktasklib
[
"dkfileutils"
]
which means that the dktasklib
package only depends on the dkfileutils
package.
This functionality is also available programmatically:
import os
from pydeps.pydeps import externals
# the directory that contains setup.py (one level up from actual package):
os.chdir('package-directory')
print externals('mypackage')
Version 1.2.5: The defaults are now sensible, such that:
shell> pydeps mypackage
will likely do what you want. It is the same as pydeps --show --max-bacon=2 mypackage
which means display the dependency graph in your browser, but limit it to two hops (which includes only the modules that your module imports -- not continuing down the import chain). The old default behavior is available with pydeps --noshow --max-bacon=0 mypackage
.
Usage
This is the result of running pydeps
on itself (pydeps pydeps
):
(full disclosure: this is for an early version of pydeps)
Bacon
pydeps
also contains an Erdős-like scoring function (a.k.a. Bacon number, from Six degrees of Kevin Bacon (http://en.wikipedia.org/wiki/Six_Degrees_of_Kevin_Bacon) that lets you filter out modules that are more than a given number of 'hops' away from the module you're interested in. This is useful for finding the interface a module has to the rest of the world.
To find pydeps' interface to the Python stdlib (less some very common modules).
shell> pydeps pydeps --show --max-bacon 2 --pylib -x os re types _* enum
--max-bacon 2
(the default) gives the modules that are at most 2 hops away, and modules that belong together have similar colors. Compare that to the output with the --max-bacon=0
(infinite) filter:
.pydeps
All options can also be set in a .pydeps
file using .ini
file syntax (parsable by ConfigParser
). Command line options override options in the .pydeps
file in the current directory, which again overrides options in the user's home directory (%USERPROFILE%\.pydeps
on Windows and ${HOME}/.pydeps
otherwise).
An example .pydeps file:
[pydeps]
max_bacon = 2
verbose = 0
pylib = False
exclude =
os
re
sys
collections
__future__
Import cycles
pydeps
can detect and display cycles with the --show-cycles
parameter. This will only display the cycles, and for big libraries it is not a particularly fast operation. Given a folder with the following contents (this uses yaml to define a directory structure, like in the tests):
relimp:
- __init__.py
- a.py: |
from . import b
- b.py: |
from . import a
pydeps relimp --show-cycles
displays:
Clustering externals
Running pydeps pydeps --max-bacon=4 on version 1.8.0 of pydeps gives the following graph:
If you are not interested in the internal structure of external modules, you can add the --cluster
flag, which will collapse external modules into folder-shaped objects:
shell> pydeps pydeps --max-bacon=4 --cluster
To see the internal structure and delineate external modules, use the --max-cluster-size
flag, which controls how many nodes can be in a cluster before it is collapsed to a folder icon:
shell> pydeps pydeps --max-bacon=4 --cluster --max-cluster-size=1000
or, using a smaller max-cluster-size:
shell> pydeps pydeps --max-bacon=4 --cluster --max-cluster-size=3
To remove clusters with too few nodes, use the --min-cluster-size
flag:
shell> pydeps pydeps --max-bacon=4 --cluster --max-cluster-size=3 --min-cluster-size=2
In some situations it can be useful to draw the target module as a cluster:
shell> pydeps pydeps --max-bacon=4 --cluster --max-cluster-size=3 --min-cluster-size=2 --keep-target-cluster
..and since the cluster boxes include the module name, we can remove those prefixes:
shell> pydeps pydeps --max-bacon=4 --cluster --max-cluster-size=3 --min-cluster-size=2 --keep-target-cluster --rmprefix pydeps. stdlib_list.
Intermediate format
An attempt has been made to keep the intermediate formats readable, eg. the output from pydeps --show-deps ..
looks like this:
...
"pydeps.mf27": {
"imported_by": [
"__main__",
"pydeps.py2depgraph"
],
"kind": "imp.PY_SOURCE",
"name": "pydeps.mf27",
"path": "pydeps\\mf27.py"
},
"pydeps.py2depgraph": {
"imported_by": [
"__main__",
"pydeps.pydeps"
],
"imports": [
"pydeps.depgraph",
"pydeps.mf27"
],
"kind": "imp.PY_SOURCE",
"name": "pydeps.py2depgraph",
"path": "pydeps\\py2depgraph.py"
}, ...
Usage (parameters)
usage: pydeps [-h] [--debug] [--config FILE] [--no-config] [--version]
[-L LOG] [-v] [-o file] [-T FORMAT] [--display PROGRAM]
[--noshow] [--show-deps] [--show-raw-deps] [--show-dot]
[--nodot] [--no-output] [--show-cycles] [--debug-mf INT]
[--noise-level INT] [--max-bacon INT] [--pylib] [--pylib-all]
[--include-missing] [-x PATTERN [PATTERN ...]]
[-xx MODULE [MODULE ...]] [--only MODULE_PATH [MODULE_PATH ...]]
[--externals] [--reverse] [--cluster] [--min-cluster-size INT]
[--max-cluster-size INT] [--keep-target-cluster]
[--rmprefix PREFIX [PREFIX ...]]
fname
positional arguments:fname filenameoptional arguments:
| --- | --- |
| -h, --help | show this help message and exit |
| --config FILE | specify config file |
| --no-config | disable processing of config files |
| --version | print pydeps version |
| -L LOG, --log LOG |
| | set log-level to one of CRITICAL, ERROR, WARNING, INFO, DEBUG, NOTSET. |
| -v, --verbose | be more verbose (-vv, -vvv for more verbosity) |
| -o file | write output to 'file' |
| -T FORMAT | output format (svg|png) |
| --display PROGRAM |
| | program to use to display the graph (png or svg file depending on the T parameter) |
| --noshow | don't call external program to display graph |
| --show-deps | show output of dependency analysis |
| --show-raw-deps |
| | show output of dependency analysis before removing skips |
| --show-dot | show output of dot conversion |
| --nodot | skip dot conversion |
| --no-output | don't create .svg/.png file, implies --no-show (-t/-o will be ignored) |
| --show-cycles | show only import cycles |
| --debug | turn on all the show and verbose options (mainly for debugging pydeps itself) |
| --noise-level INT |
| | exclude sources or sinks with degree greater than noise-level |
| --max-bacon INT |
| | exclude nodes that are more than n hops away (default=2, 0 -> infinite) |
| --pylib | include python std lib modules |
| --pylib-all | include python all std lib modules (incl. C modules) |
| --x PATTERN, --exclude PATTERN |
| | input files to skip (e.g. foo.*), multiple patterns can be provided |
| --xx MODULE, --exclude-exact MODULE |
| | same as --exclude, except requires the full match. -xx foo.bar will exclude foo.bar, but not foo.bar.blob |
| --only MODULE_PATH |
| | only include modules that start with MODULE_PATH, multiple paths can be provided |
| --externals | create list of direct external dependencies |
| --reverse | draw arrows to (instead of from) imported modules |
| --cluster | draw external dependencies as separate clusters |
| --min-cluster-size INT |
| | the minimum number of nodes a dependency must have before being clustered (default=0) |
| --max-cluster-size INT |
| | the maximum number of nodes a dependency can have before the cluster is collapsed to a single node (default=0) |
| --keep-target-cluster |
| | draw target module as a cluster |
| --rmprefix PREFIX |
| | remove PREFIX from the displayed name of the nodes (multiple prefixes can be provided) |
You can of course import pydeps
from Python (look in the tests/test_relative_imports.py
file for examples.
Contributing
- Fork it
- It is appreciated (but not required) if you raise an issue first: https://github.com/thebjorn/pydeps/issues
- Create your feature branch (git checkout -b my-new-feature)
- Commit your changes (git commit -am 'Add some feature')
- Push to the branch (git push origin my-new-feature)
- Create new Pull Request