Merge pull request #60 from Dunedan/graphviz

Add different output options for dependency graph
This commit is contained in:
Vineet Naik 2016-12-28 21:11:54 +05:30 committed by GitHub
commit 6e095e658f
3 changed files with 74 additions and 2 deletions

View File

@ -201,6 +201,16 @@ tools.
$ python pipdeptree.py --json $ python pipdeptree.py --json
The dependency graph can be layed out as any of the formats supported by
GraphViz`GraphViz<http://www.graphviz.org/>`_:
.. code-block:: bash
$ pipdeptree --graph-output dot > dependencies.dot
$ pipdeptree --graph-output pdf > dependencies.pdf
$ pipdeptree --graph-output png > dependencies.png
$ pipdeptree --graph-output svg > dependencies.svg
Usage Usage
----- -----
@ -233,6 +243,10 @@ Usage
-j, --json Display dependency tree as json. This will yield "raw" -j, --json Display dependency tree as json. This will yield "raw"
output that may be used by external tools. This option output that may be used by external tools. This option
overrides all other options. overrides all other options.
--graph-output OUTPUT_FORMAT
Print a dependency graph in the specified output
format. Available are all formats supported by
GraphViz, e.g.: dot, jpeg, pdf, png, svg
Known Issues Known Issues

View File

@ -14,6 +14,8 @@ except ImportError:
import pip import pip
import pkg_resources import pkg_resources
# inline:
# from graphviz import backend, Digraph
__version__ = '0.8.0' __version__ = '0.8.0'
@ -339,6 +341,52 @@ def jsonify_tree(tree, indent):
indent=indent) indent=indent)
def dump_graphviz(tree, output_format='dot'):
"""Output dependency graph as one of the supported GraphViz output formats.
:param dict tree: dependency graph
:param string output_format: output format
:returns: representation of tree in the specified output format
:rtype: str or binary representation depending on the output format
"""
try:
from graphviz import backend, Digraph
except ImportError:
print('graphviz is not available, but necessary for the output '
'option. Please install it.', file=sys.stderr)
sys.exit(1)
if output_format not in backend.FORMATS:
print('{} is no supported output format.'.format(output_format),
file=sys.stderr)
print('Supported formats are: {}'.format(
', '.join(sorted(backend.FORMATS))), file=sys.stderr)
sys.exit(1)
graph = Digraph(format=output_format)
for package, deps in tree.items():
project_name = package.project_name
label = '{}\n{}'.format(project_name, package.version)
graph.node(project_name, label=label)
for dep in deps:
label = dep.version_spec
if not label:
label = 'any'
graph.edge(project_name, dep.project_name, label=label)
# Allow output of dot format, even if GraphViz isn't installed.
if output_format == 'dot':
return graph.source
# As it's unknown if the selected output format is binary or not, try to
# decode it as UTF8 and only print it out in binary if that's not possible.
try:
return graph.pipe().decode('utf-8')
except UnicodeDecodeError:
return graph.pipe()
def conflicting_deps(tree): def conflicting_deps(tree):
"""Returns dependencies which are not present or conflict with the """Returns dependencies which are not present or conflict with the
requirements of other packages. requirements of other packages.
@ -418,6 +466,12 @@ def main():
'"raw" output that may be used by external tools. ' '"raw" output that may be used by external tools. '
'This option overrides all other options.' 'This option overrides all other options.'
)) ))
parser.add_argument('--graph-output', dest='output_format',
help=(
'Print a dependency graph in the specified output '
'format. Available are all formats supported by '
'GraphViz, e.g.: dot, jpeg, pdf, png, svg'
))
args = parser.parse_args() args = parser.parse_args()
pkgs = pip.get_installed_distributions(local_only=args.local_only) pkgs = pip.get_installed_distributions(local_only=args.local_only)
@ -428,6 +482,9 @@ def main():
if args.json: if args.json:
print(jsonify_tree(tree, indent=4)) print(jsonify_tree(tree, indent=4))
return 0 return 0
elif args.output_format:
print(dump_graphviz(tree, output_format=args.output_format))
return 0
return_code = 0 return_code = 0
@ -440,10 +497,10 @@ def main():
file=sys.stderr) file=sys.stderr)
for p, reqs in conflicting.items(): for p, reqs in conflicting.items():
pkg = p.render_as_root(False) pkg = p.render_as_root(False)
print('* %s' % pkg, file=sys.stderr) print('* {}'.format(pkg), file=sys.stderr)
for req in reqs: for req in reqs:
req_str = req.render_as_branch(False) req_str = req.render_as_branch(False)
print(' - %s' % req_str, file=sys.stderr) print(' - {}'.format(req_str), file=sys.stderr)
print('-'*72, file=sys.stderr) print('-'*72, file=sys.stderr)
cyclic = cyclic_deps(tree) cyclic = cyclic_deps(tree)

View File

@ -33,6 +33,7 @@ setup(
description='Command line utility to show dependency tree of packages', description='Command line utility to show dependency tree of packages',
long_description=long_desc, long_description=long_desc,
install_requires=install_requires, install_requires=install_requires,
extras_require={'graphviz': ['graphviz']},
py_modules=['pipdeptree'], py_modules=['pipdeptree'],
entry_points={ entry_points={
'console_scripts': [ 'console_scripts': [