Skip to content

Commit

Permalink
Fix #36 -- switch to graphviz 0.18 (#37)
Browse files Browse the repository at this point in the history
* Fix #36 -- switch to graphviz 0.18

Use staticmethods instead of "%" operator. This reflects xflr6/graphviz@17df613

* Use quoting instead of lang

Reflects xflr6/graphviz@673261d

* Use new `encoding` argument instead of manual decoding

https://github.com/xflr6/graphviz/blob/master/CHANGES.rst#version-018
>Add optional keyword-only encoding argument to pipe(). Returns the decoded stdout from the rendering process (e.g. format='svg'). Delegates encoding/decoding to subprocess in the common case (input and output encoding are the same, e.g. default encoding='utf-8'). Used by the Jupyter notebook integration.

* Adjust tests to handle newlines

https://github.com/xflr6/graphviz/blob/master/CHANGES.rst#version-018
>Change of undocumented behaviour: When iterating over a Graph, Digraph, or Source instance, the yielded lines now include a final newline ('\n'). This mimics iteration over file object lines in text mode.

* Pin graphviz>=0.18

* Blackify

* Fix one more test
  • Loading branch information
amureki authored Nov 8, 2021
1 parent 8ea4038 commit 649e294
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 44 deletions.
4 changes: 2 additions & 2 deletions joeflow/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ def get_graph_svg(cls):
"""
graph = cls.get_graph()
graph.format = "svg"
return SafeString(graph.pipe().decode("utf-8")) # nosec
return SafeString(graph.pipe(encoding="utf-8")) # nosec

get_graph_svg.short_description = t("graph")

Expand Down Expand Up @@ -326,7 +326,7 @@ def get_instance_graph_svg(self, output_format="svg"):
"""
graph = self.get_instance_graph()
graph.format = output_format
return SafeString(graph.pipe().decode("utf-8")) # nosec
return SafeString(graph.pipe(encoding="utf-8")) # nosec

get_instance_graph_svg.short_description = t("instance graph")

Expand Down
16 changes: 8 additions & 8 deletions joeflow/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,20 +44,20 @@ def __init__(self, *args, **kwargs):
def __iter__(self, subgraph=False):
"""Yield the DOT source code line by line (as graph or subgraph)."""
if self.comment:
yield self._comment % self.comment
yield self._comment(self.comment)

if subgraph:
if self.strict:
raise ValueError("subgraphs cannot be strict")
head = self._subgraph if self.name else self._subgraph_plain
else:
head = self._head_strict if self.strict else self._head
yield head % (self._quote(self.name) + " " if self.name else "")
yield head(self._quote(self.name) + " " if self.name else "")

for kw in ("graph", "node", "edge"):
attrs = getattr(self, "%s_attr" % kw)
if attrs:
yield self._attr % (kw, self._attr_list(None, attrs))
yield self._attr(kw, self._attr_list(None, attrs))

yield from self.body

Expand All @@ -66,16 +66,16 @@ def __iter__(self, subgraph=False):
label = attrs.pop("label", None)
_attributes = attrs.pop("_attributes", None)
attr_list = self._attr_list(label, attrs, _attributes)
yield self._node % (name, attr_list)
yield self._node(name, attr_list)

for edge, attrs in sorted(self._edges.items()):
head_name, tail_name = edge
tail_name, head_name = edge
tail_name = self._quote_edge(tail_name)
head_name = self._quote_edge(head_name)
label = attrs.pop("label", None)
_attributes = attrs.pop("_attributes", None)
attr_list = self._attr_list(label, attrs, _attributes)
yield self._edge % (head_name, tail_name, attr_list)
yield self._edge(tail=tail_name, head=head_name, attr=attr_list)

yield self._tail

Expand All @@ -89,10 +89,10 @@ def edge(self, tail_name, head_name, **attrs):
def _quote(identifier, *args, **kwargs):
"""Remove underscores from labels."""
identifier = identifier.replace("_", " ")
return gv.lang.quote(identifier, *args, **kwargs)
return gv.quoting.quote(identifier, *args, **kwargs)

@staticmethod
def _quote_edge(identifier):
"""Remove underscores from labels."""
identifier = identifier.replace("_", " ")
return gv.lang.quote_edge(identifier)
return gv.quoting.quote_edge(identifier)
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ packages = joeflow
install_requires =
django>=2.2
django-appconf
graphviz
graphviz>=0.18
setup_requires =
setuptools_scm
sphinx
Expand Down
16 changes: 9 additions & 7 deletions tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ def test_get_graph(self, fixturedir):
with open(str(fixturedir / "simpleworkflow.dot")) as fp:
expected_graph = fp.read().splitlines()
print(str(graph))
assert set(graph) == set(expected_graph)
assert set(str(graph).splitlines()) == set(expected_graph)

def test_get_graph_svg(self, fixturedir):
svg = workflows.SimpleWorkflow.get_graph_svg()
Expand All @@ -121,7 +121,9 @@ def test_get_instance_graph(self, db, fixturedir):
graph = wf.get_instance_graph()
print(str(graph))
with open(str(fixturedir / "simpleworkflow_instance.dot")) as fp:
assert set(graph) == set(fp.read().replace("{url}", task_url).splitlines())
assert set(str(graph).splitlines()) == set(
fp.read().replace("{url}", task_url).splitlines()
)

def test_get_instance_graph__override(
self, db, stub_worker, fixturedir, admin_client
Expand All @@ -136,14 +138,14 @@ def test_get_instance_graph__override(
print(str(graph))

assert (
f'\t"{task.name} {task.pk}" [peripheries=1 style="filled, rounded, dashed"]'
f'\t"{task.name} {task.pk}" [peripheries=1 style="filled, rounded, dashed"]\n'
in list(graph)
)
assert (
f'\t"save the princess" -> "{task.name} {task.pk}" [style=dashed]'
f'\t"save the princess" -> "{task.name} {task.pk}" [style=dashed]\n'
in list(graph)
)
assert f'\t"{task.name} {task.pk}" -> end [style=dashed]' in list(graph)
assert f'\t"{task.name} {task.pk}" -> end [style=dashed]\n' in list(graph)

def test_get_instance_graph__obsolete(self, db, fixturedir, admin_client):
workflow = workflows.SimpleWorkflow.objects.create()
Expand All @@ -159,8 +161,8 @@ def test_get_instance_graph__obsolete(self, db, fixturedir, admin_client):
'\tobsolete [color=black fontcolor=black peripheries=1 style="filled, dashed, bold"]'
in str(graph)
)
assert '\t"start method" -> obsolete [style=dashed]' in list(graph)
assert "\tobsolete -> end [style=dashed]" in list(graph)
assert '\t"start method" -> obsolete [style=dashed]\n' in list(graph)
assert "\tobsolete -> end [style=dashed]\n" in list(graph)

def test_get_instance_graph_svg(self, db, fixturedir):
wf = workflows.SimpleWorkflow.start_method()
Expand Down
52 changes: 26 additions & 26 deletions tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,30 +6,30 @@ def test_node(self):
graph = NoDashDiGraph()
graph.node("foo", color="blue")
assert list(graph) == [
"digraph {",
"\tfoo [color=blue]",
"}",
"digraph {\n",
"\tfoo [color=blue]\n",
"}\n",
]
graph.node("foo", color="red")
assert list(graph) == [
"digraph {",
"\tfoo [color=red]",
"}",
"digraph {\n",
"\tfoo [color=red]\n",
"}\n",
]

def test_edge(self):
graph = NoDashDiGraph()
graph.edge("foo", "bar", color="blue")
assert list(graph) == [
"digraph {",
"\tfoo -> bar [color=blue]",
"}",
"digraph {\n",
"\tfoo -> bar [color=blue]\n",
"}\n",
]
graph.edge("foo", "bar", color="red")
assert list(graph) == [
"digraph {",
"\tfoo -> bar [color=red]",
"}",
"digraph {\n",
"\tfoo -> bar [color=red]\n",
"}\n",
]

def test_iter(self):
Expand All @@ -40,13 +40,13 @@ def test_iter(self):
graph.comment = "This is a comment."
print(str(graph))
assert list(graph.__iter__()) == [
"// This is a comment.",
"digraph {",
"\tnode [style=filled]",
"\tbar [color=green]",
"\tfoo [color=red]",
"\tfoo -> bar [color=blue]",
"}",
"// This is a comment.\n",
"digraph {\n",
"\tnode [style=filled]\n",
"\tbar [color=green]\n",
"\tfoo [color=red]\n",
"\tfoo -> bar [color=blue]\n",
"}\n",
]

def test_iter__subgraph(self):
Expand All @@ -57,13 +57,13 @@ def test_iter__subgraph(self):
graph.comment = "This is a comment."
print(str(graph))
assert list(graph.__iter__(subgraph=True)) == [
"// This is a comment.",
"{",
"\tnode [style=filled]",
"\tbar [color=green]",
"\tfoo [color=red]",
"\tfoo -> bar [color=blue]",
"}",
"// This is a comment.\n",
"{\n",
"\tnode [style=filled]\n",
"\tbar [color=green]\n",
"\tfoo [color=red]\n",
"\tfoo -> bar [color=blue]\n",
"}\n",
]

def test_quote(self):
Expand Down

0 comments on commit 649e294

Please sign in to comment.