Skip to content

Commit 649e294

Browse files
authored
Fix #36 -- switch to graphviz 0.18 (#37)
* 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
1 parent 8ea4038 commit 649e294

File tree

5 files changed

+46
-44
lines changed

5 files changed

+46
-44
lines changed

joeflow/models.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ def get_graph_svg(cls):
236236
"""
237237
graph = cls.get_graph()
238238
graph.format = "svg"
239-
return SafeString(graph.pipe().decode("utf-8")) # nosec
239+
return SafeString(graph.pipe(encoding="utf-8")) # nosec
240240

241241
get_graph_svg.short_description = t("graph")
242242

@@ -326,7 +326,7 @@ def get_instance_graph_svg(self, output_format="svg"):
326326
"""
327327
graph = self.get_instance_graph()
328328
graph.format = output_format
329-
return SafeString(graph.pipe().decode("utf-8")) # nosec
329+
return SafeString(graph.pipe(encoding="utf-8")) # nosec
330330

331331
get_instance_graph_svg.short_description = t("instance graph")
332332

joeflow/utils.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -44,20 +44,20 @@ def __init__(self, *args, **kwargs):
4444
def __iter__(self, subgraph=False):
4545
"""Yield the DOT source code line by line (as graph or subgraph)."""
4646
if self.comment:
47-
yield self._comment % self.comment
47+
yield self._comment(self.comment)
4848

4949
if subgraph:
5050
if self.strict:
5151
raise ValueError("subgraphs cannot be strict")
5252
head = self._subgraph if self.name else self._subgraph_plain
5353
else:
5454
head = self._head_strict if self.strict else self._head
55-
yield head % (self._quote(self.name) + " " if self.name else "")
55+
yield head(self._quote(self.name) + " " if self.name else "")
5656

5757
for kw in ("graph", "node", "edge"):
5858
attrs = getattr(self, "%s_attr" % kw)
5959
if attrs:
60-
yield self._attr % (kw, self._attr_list(None, attrs))
60+
yield self._attr(kw, self._attr_list(None, attrs))
6161

6262
yield from self.body
6363

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

7171
for edge, attrs in sorted(self._edges.items()):
72-
head_name, tail_name = edge
72+
tail_name, head_name = edge
7373
tail_name = self._quote_edge(tail_name)
7474
head_name = self._quote_edge(head_name)
7575
label = attrs.pop("label", None)
7676
_attributes = attrs.pop("_attributes", None)
7777
attr_list = self._attr_list(label, attrs, _attributes)
78-
yield self._edge % (head_name, tail_name, attr_list)
78+
yield self._edge(tail=tail_name, head=head_name, attr=attr_list)
7979

8080
yield self._tail
8181

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

9494
@staticmethod
9595
def _quote_edge(identifier):
9696
"""Remove underscores from labels."""
9797
identifier = identifier.replace("_", " ")
98-
return gv.lang.quote_edge(identifier)
98+
return gv.quoting.quote_edge(identifier)

setup.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ packages = joeflow
4646
install_requires =
4747
django>=2.2
4848
django-appconf
49-
graphviz
49+
graphviz>=0.18
5050
setup_requires =
5151
setuptools_scm
5252
sphinx

tests/test_models.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ def test_get_graph(self, fixturedir):
109109
with open(str(fixturedir / "simpleworkflow.dot")) as fp:
110110
expected_graph = fp.read().splitlines()
111111
print(str(graph))
112-
assert set(graph) == set(expected_graph)
112+
assert set(str(graph).splitlines()) == set(expected_graph)
113113

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

126128
def test_get_instance_graph__override(
127129
self, db, stub_worker, fixturedir, admin_client
@@ -136,14 +138,14 @@ def test_get_instance_graph__override(
136138
print(str(graph))
137139

138140
assert (
139-
f'\t"{task.name} {task.pk}" [peripheries=1 style="filled, rounded, dashed"]'
141+
f'\t"{task.name} {task.pk}" [peripheries=1 style="filled, rounded, dashed"]\n'
140142
in list(graph)
141143
)
142144
assert (
143-
f'\t"save the princess" -> "{task.name} {task.pk}" [style=dashed]'
145+
f'\t"save the princess" -> "{task.name} {task.pk}" [style=dashed]\n'
144146
in list(graph)
145147
)
146-
assert f'\t"{task.name} {task.pk}" -> end [style=dashed]' in list(graph)
148+
assert f'\t"{task.name} {task.pk}" -> end [style=dashed]\n' in list(graph)
147149

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

165167
def test_get_instance_graph_svg(self, db, fixturedir):
166168
wf = workflows.SimpleWorkflow.start_method()

tests/test_utils.py

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -6,30 +6,30 @@ def test_node(self):
66
graph = NoDashDiGraph()
77
graph.node("foo", color="blue")
88
assert list(graph) == [
9-
"digraph {",
10-
"\tfoo [color=blue]",
11-
"}",
9+
"digraph {\n",
10+
"\tfoo [color=blue]\n",
11+
"}\n",
1212
]
1313
graph.node("foo", color="red")
1414
assert list(graph) == [
15-
"digraph {",
16-
"\tfoo [color=red]",
17-
"}",
15+
"digraph {\n",
16+
"\tfoo [color=red]\n",
17+
"}\n",
1818
]
1919

2020
def test_edge(self):
2121
graph = NoDashDiGraph()
2222
graph.edge("foo", "bar", color="blue")
2323
assert list(graph) == [
24-
"digraph {",
25-
"\tfoo -> bar [color=blue]",
26-
"}",
24+
"digraph {\n",
25+
"\tfoo -> bar [color=blue]\n",
26+
"}\n",
2727
]
2828
graph.edge("foo", "bar", color="red")
2929
assert list(graph) == [
30-
"digraph {",
31-
"\tfoo -> bar [color=red]",
32-
"}",
30+
"digraph {\n",
31+
"\tfoo -> bar [color=red]\n",
32+
"}\n",
3333
]
3434

3535
def test_iter(self):
@@ -40,13 +40,13 @@ def test_iter(self):
4040
graph.comment = "This is a comment."
4141
print(str(graph))
4242
assert list(graph.__iter__()) == [
43-
"// This is a comment.",
44-
"digraph {",
45-
"\tnode [style=filled]",
46-
"\tbar [color=green]",
47-
"\tfoo [color=red]",
48-
"\tfoo -> bar [color=blue]",
49-
"}",
43+
"// This is a comment.\n",
44+
"digraph {\n",
45+
"\tnode [style=filled]\n",
46+
"\tbar [color=green]\n",
47+
"\tfoo [color=red]\n",
48+
"\tfoo -> bar [color=blue]\n",
49+
"}\n",
5050
]
5151

5252
def test_iter__subgraph(self):
@@ -57,13 +57,13 @@ def test_iter__subgraph(self):
5757
graph.comment = "This is a comment."
5858
print(str(graph))
5959
assert list(graph.__iter__(subgraph=True)) == [
60-
"// This is a comment.",
61-
"{",
62-
"\tnode [style=filled]",
63-
"\tbar [color=green]",
64-
"\tfoo [color=red]",
65-
"\tfoo -> bar [color=blue]",
66-
"}",
60+
"// This is a comment.\n",
61+
"{\n",
62+
"\tnode [style=filled]\n",
63+
"\tbar [color=green]\n",
64+
"\tfoo [color=red]\n",
65+
"\tfoo -> bar [color=blue]\n",
66+
"}\n",
6767
]
6868

6969
def test_quote(self):

0 commit comments

Comments
 (0)