diff --git a/johnnydep/__init__.py b/johnnydep/__init__.py index 9712078..b041af1 100644 --- a/johnnydep/__init__.py +++ b/johnnydep/__init__.py @@ -1,5 +1,5 @@ """Display dependency tree of Python distribution""" -__version__ = "1.17.3" +__version__ = "1.17.4" from johnnydep.lib import * diff --git a/johnnydep/cli.py b/johnnydep/cli.py index 6869713..0a393d6 100644 --- a/johnnydep/cli.py +++ b/johnnydep/cli.py @@ -57,7 +57,7 @@ def main(argv=None, stdout=None): ) parser.add_argument( "--no-deps", - help="Don't recurse the dependency tree. Has no effect for output format 'human'", + help="Don't recurse the dependency tree", dest="recurse", action="store_false", ) @@ -87,6 +87,11 @@ def main(argv=None, stdout=None): extra_index_url=args.extra_index_url, ignore_errors=args.ignore_errors, ) - print(dist.serialise(fields=args.fields, format=args.output_format, recurse=args.recurse), file=stdout) + rendered = dist.serialise( + fields=args.fields, + format=args.output_format, + recurse=args.recurse, + ) + print(rendered, file=stdout) if (args.recurse and has_error(dist)) or (not args.recurse and dist.error is not None): sys.exit(1) diff --git a/johnnydep/dot.py b/johnnydep/dot.py index ea0b890..509cd9e 100644 --- a/johnnydep/dot.py +++ b/johnnydep/dot.py @@ -1,12 +1,13 @@ from anytree import LevelOrderIter import johnnydep +from johnnydep.compat import dict from johnnydep.util import CircularMarker template = """\ %(comment)s -strict digraph %(title)s { +digraph %(title)s { %(edges)s } """ @@ -36,6 +37,7 @@ def jd2dot(dist, comment=None): label = ' [label="{}"]'.format(spec) if spec else "" edge = '"{}" -> "{}"'.format(parent_node_name, node_name) edges.append(edge + label + ";") + edges = list(dict.fromkeys(edges)) # order-preserving de-dupe edges = "\n ".join(edges) if not edges: # project with no dependencies - it's just a single node diff --git a/johnnydep/lib.py b/johnnydep/lib.py index ff8f45b..08367b4 100644 --- a/johnnydep/lib.py +++ b/johnnydep/lib.py @@ -281,6 +281,8 @@ def serialise(self, fields=("name", "summary"), recurse=True, format=None): if format == "pinned": # user-specified fields are ignored/invalid in this case fields = ("pinned",) + if format == "dot": + return jd2dot(self) data = [dict([(f, getattr(self, f, None)) for f in fields])] if format == "human": table = gen_table(self, extra_cols=fields) @@ -302,8 +304,6 @@ def serialise(self, fields=("name", "summary"), recurse=True, format=None): result = "\n".join([toml.dumps(d) for d in data]) elif format == "pinned": result = "\n".join([d["pinned"] for d in data]) - elif format == "dot": - result = jd2dot(self) else: raise JohnnyError("Unsupported format") return result diff --git a/johnnydep/util.py b/johnnydep/util.py index 4a3f2a7..9739666 100644 --- a/johnnydep/util.py +++ b/johnnydep/util.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals import json +import structlog from argparse import ArgumentTypeError from subprocess import check_output from subprocess import CalledProcessError @@ -45,6 +46,7 @@ def __init__(self, summary, parent): self.name = CircularMarker.glyph self.summary = summary self.parent = parent + self.log = structlog.get_logger() def __getattr__(self, name): if name.startswith("_"): diff --git a/tests/test_dot.py b/tests/test_dot.py index 74712f7..73f03de 100644 --- a/tests/test_dot.py +++ b/tests/test_dot.py @@ -15,7 +15,7 @@ def test_dot_export(make_dist): expected = dedent( """ # generated by https://github.com/wimglenn/johnnydep v1.0 - strict digraph parent { + digraph parent { "parent[x]" -> "child" [label=">0.1"]; "parent[x]" -> "Extra"; } @@ -34,7 +34,7 @@ def test_nodupes(make_dist): expected = dedent( """ // diamond - strict digraph root { + digraph root { "root" -> "dep1"; "root" -> "dep2"; "dep1" -> "leaf"; @@ -54,7 +54,7 @@ def test_circular_graph(make_dist): expected = dedent( """ # cyclic, oh no! - strict digraph dist1 { + digraph dist1 { "dist1" -> "dist2"; "dist2" -> "dist3"; "dist3" -> "dist1"; @@ -70,7 +70,7 @@ def test_graph_with_no_edges(make_dist): actual = jd2dot(dist, comment="") expected = dedent( """ - strict digraph lonely { + digraph lonely { "lonely"; } """ diff --git a/tests/test_util.py b/tests/test_util.py index 802fd9f..010e7b8 100644 --- a/tests/test_util.py +++ b/tests/test_util.py @@ -4,7 +4,10 @@ import pytest +from johnnydep import JohnnyDist +from johnnydep.cli import FIELDS from johnnydep.compat import text_type +from johnnydep.util import CircularMarker from johnnydep.util import python_interpreter @@ -46,3 +49,9 @@ def test_good_python_env(): "sys_platform", "wheel_version", ] + + +def test_placeholder_serializes(): + # this just checks that the placeholder can render to text without issue + dist = CircularMarker(summary=".", parent=None) + JohnnyDist.serialise(dist, fields=FIELDS, format="human")