new: dev: Added Tox and CI integration.
This commit is contained in:
parent
fa561ada17
commit
b074bb2298
7
.travis.yml
Normal file
7
.travis.yml
Normal file
@ -0,0 +1,7 @@
|
||||
language: python
|
||||
install:
|
||||
- pip install tox coveralls
|
||||
script:
|
||||
- tox
|
||||
after_success:
|
||||
- coveralls
|
@ -28,4 +28,4 @@ PyDotPlus module entry.
|
||||
"""
|
||||
|
||||
from .parser import * # noqa
|
||||
from .graph import * # noqa
|
||||
from .graphviz import * # noqa
|
||||
|
@ -27,13 +27,13 @@
|
||||
Graphviz's dot language parser.
|
||||
|
||||
The dotparser parses graphviz files in dot and dot files and transforms them
|
||||
into a class representation defined by pydot.
|
||||
into a class representation defined by pydotplus.
|
||||
"""
|
||||
|
||||
from __future__ import division, print_function
|
||||
|
||||
import sys
|
||||
import pydot
|
||||
import pydotplus
|
||||
import codecs
|
||||
|
||||
from pyparsing import __version__ as pyparsing_version
|
||||
@ -104,7 +104,7 @@ def push_top_graph_stmt(str, loc, toks):
|
||||
elif element in ['graph', 'digraph']:
|
||||
attrs = {}
|
||||
|
||||
g = pydot.Dot(graph_type=element, **attrs)
|
||||
g = pydotplus.Dot(graph_type=element, **attrs)
|
||||
attrs['type'] = element
|
||||
|
||||
top_graphs.append(g)
|
||||
@ -112,7 +112,7 @@ def push_top_graph_stmt(str, loc, toks):
|
||||
elif isinstance(element, basestring):
|
||||
g.set_name(element)
|
||||
|
||||
elif isinstance(element, pydot.Subgraph):
|
||||
elif isinstance(element, pydotplus.Subgraph):
|
||||
g.obj_dict['attributes'].update(element.obj_dict['attributes'])
|
||||
g.obj_dict['edges'].update(element.obj_dict['edges'])
|
||||
g.obj_dict['nodes'].update(element.obj_dict['nodes'])
|
||||
@ -142,7 +142,7 @@ def update_parent_graph_hierarchy(g, parent_graph=None, level=0):
|
||||
parent_graph = g
|
||||
|
||||
for key_name in ('edges',):
|
||||
if isinstance(g, pydot.frozendict):
|
||||
if isinstance(g, pydotplus.frozendict):
|
||||
item_dict = g
|
||||
else:
|
||||
item_dict = g.obj_dict
|
||||
@ -163,10 +163,14 @@ def update_parent_graph_hierarchy(g, parent_graph=None, level=0):
|
||||
for idx, vertex in enumerate(obj['points']):
|
||||
if isinstance(
|
||||
vertex,
|
||||
(pydot.Graph, pydot.Subgraph, pydot.Cluster)
|
||||
(
|
||||
pydotplus.Graph,
|
||||
pydotplus.Subgraph,
|
||||
pydotplus.Cluster
|
||||
)
|
||||
):
|
||||
vertex.set_parent_graph(parent_graph)
|
||||
if isinstance(vertex, pydot.frozendict):
|
||||
if isinstance(vertex, pydotplus.frozendict):
|
||||
if vertex['parent_graph'] is g:
|
||||
pass
|
||||
else:
|
||||
@ -194,15 +198,15 @@ def add_elements(g, toks,
|
||||
defaults_edge = {}
|
||||
|
||||
for elm_idx, element in enumerate(toks):
|
||||
if isinstance(element, (pydot.Subgraph, pydot.Cluster)):
|
||||
if isinstance(element, (pydotplus.Subgraph, pydotplus.Cluster)):
|
||||
add_defaults(element, defaults_graph)
|
||||
g.add_subgraph(element)
|
||||
|
||||
elif isinstance(element, pydot.Node):
|
||||
elif isinstance(element, pydotplus.Node):
|
||||
add_defaults(element, defaults_node)
|
||||
g.add_node(element)
|
||||
|
||||
elif isinstance(element, pydot.Edge):
|
||||
elif isinstance(element, pydotplus.Edge):
|
||||
add_defaults(element, defaults_edge)
|
||||
g.add_edge(element)
|
||||
|
||||
@ -214,15 +218,15 @@ def add_elements(g, toks,
|
||||
|
||||
elif isinstance(element, DefaultStatement):
|
||||
if element.default_type == 'graph':
|
||||
default_graph_attrs = pydot.Node('graph', **element.attrs)
|
||||
default_graph_attrs = pydotplus.Node('graph', **element.attrs)
|
||||
g.add_node(default_graph_attrs)
|
||||
|
||||
elif element.default_type == 'node':
|
||||
default_node_attrs = pydot.Node('node', **element.attrs)
|
||||
default_node_attrs = pydotplus.Node('node', **element.attrs)
|
||||
g.add_node(default_node_attrs)
|
||||
|
||||
elif element.default_type == 'edge':
|
||||
default_edge_attrs = pydot.Node('edge', **element.attrs)
|
||||
default_edge_attrs = pydotplus.Node('edge', **element.attrs)
|
||||
g.add_node(default_edge_attrs)
|
||||
defaults_edge.update(element.attrs)
|
||||
|
||||
@ -239,13 +243,13 @@ def add_elements(g, toks,
|
||||
|
||||
|
||||
def push_graph_stmt(str, loc, toks):
|
||||
g = pydot.Subgraph('')
|
||||
g = pydotplus.Subgraph('')
|
||||
add_elements(g, toks)
|
||||
return g
|
||||
|
||||
|
||||
def push_subgraph_stmt(str, loc, toks):
|
||||
g = pydot.Subgraph('')
|
||||
g = pydotplus.Subgraph('')
|
||||
|
||||
for e in toks:
|
||||
if len(e) == 3:
|
||||
@ -309,8 +313,8 @@ def push_edge_stmt(str, loc, toks):
|
||||
|
||||
e = []
|
||||
|
||||
if isinstance(toks[0][0], pydot.Graph):
|
||||
n_prev = pydot.frozendict(toks[0][0].obj_dict)
|
||||
if isinstance(toks[0][0], pydotplus.Graph):
|
||||
n_prev = pydotplus.frozendict(toks[0][0].obj_dict)
|
||||
else:
|
||||
n_prev = toks[0][0] + do_node_ports(toks[0])
|
||||
|
||||
@ -318,14 +322,18 @@ def push_edge_stmt(str, loc, toks):
|
||||
n_next_list = [[n.get_name()] for n in toks[2][0]]
|
||||
for n_next in [n for n in n_next_list]:
|
||||
n_next_port = do_node_ports(n_next)
|
||||
e.append(pydot.Edge(n_prev, n_next[0] + n_next_port, **attrs))
|
||||
e.append(pydotplus.Edge(n_prev, n_next[0] + n_next_port, **attrs))
|
||||
|
||||
elif isinstance(toks[2][0], pydot.Graph):
|
||||
elif isinstance(toks[2][0], pydotplus.Graph):
|
||||
e.append(
|
||||
pydot.Edge(n_prev, pydot.frozendict(toks[2][0].obj_dict), **attrs)
|
||||
pydotplus.Edge(
|
||||
n_prev,
|
||||
pydotplus.frozendict(toks[2][0].obj_dict),
|
||||
**attrs
|
||||
)
|
||||
)
|
||||
|
||||
elif isinstance(toks[2][0], pydot.Node):
|
||||
elif isinstance(toks[2][0], pydotplus.Node):
|
||||
node = toks[2][0]
|
||||
|
||||
if node.get_port() is not None:
|
||||
@ -333,7 +341,7 @@ def push_edge_stmt(str, loc, toks):
|
||||
else:
|
||||
name_port = node.get_name()
|
||||
|
||||
e.append(pydot.Edge(n_prev, name_port, **attrs))
|
||||
e.append(pydotplus.Edge(n_prev, name_port, **attrs))
|
||||
|
||||
elif isinstance(toks[2][0], type('')):
|
||||
for n_next in [n for n in tuple(toks)[2::2]]:
|
||||
@ -342,7 +350,7 @@ def push_edge_stmt(str, loc, toks):
|
||||
continue
|
||||
|
||||
n_next_port = do_node_ports(n_next)
|
||||
e.append(pydot.Edge(n_prev, n_next[0] + n_next_port, **attrs))
|
||||
e.append(pydotplus.Edge(n_prev, n_next[0] + n_next_port, **attrs))
|
||||
|
||||
n_prev = n_next[0] + n_next_port
|
||||
|
||||
@ -365,7 +373,7 @@ def push_node_stmt(s, loc, toks):
|
||||
if len(node_name) > 0:
|
||||
node_name = node_name[0]
|
||||
|
||||
n = pydot.Node(str(node_name), **attrs)
|
||||
n = pydotplus.Node(str(node_name), **attrs)
|
||||
return n
|
||||
|
||||
|
||||
|
8
requirements.dev.txt
Normal file
8
requirements.dev.txt
Normal file
@ -0,0 +1,8 @@
|
||||
tox
|
||||
flake8
|
||||
pytest
|
||||
pytest-cov
|
||||
coverage
|
||||
coveralls
|
||||
sphinx
|
||||
sphinx_rtd_theme
|
1
requirements.txt
Normal file
1
requirements.txt
Normal file
@ -0,0 +1 @@
|
||||
pyparsing>=2.0.1
|
@ -16,7 +16,7 @@ except ImportError:
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
import pydot
|
||||
import pydotplus
|
||||
import unittest
|
||||
|
||||
|
||||
@ -30,7 +30,7 @@ else:
|
||||
bytes = str
|
||||
|
||||
|
||||
DOT_BINARY_PATH = pydot.find_graphviz()['dot']
|
||||
DOT_BINARY_PATH = pydotplus.find_graphviz()['dot']
|
||||
TEST_DIR = './'
|
||||
REGRESSION_TESTS_DIR = os.path.join(TEST_DIR, 'graphs')
|
||||
MY_REGRESSION_TESTS_DIR = os.path.join(TEST_DIR, 'my_tests')
|
||||
@ -44,21 +44,23 @@ class TestGraphAPI(unittest.TestCase):
|
||||
|
||||
def _reset_graphs(self):
|
||||
|
||||
self.graph_directed = pydot.Graph('testgraph', graph_type='digraph')
|
||||
self.graph_directed = pydotplus.Graph(
|
||||
'testgraph', graph_type='digraph'
|
||||
)
|
||||
|
||||
def test_keep_graph_type(self):
|
||||
|
||||
g = pydot.Dot(graph_name='Test', graph_type='graph')
|
||||
g = pydotplus.Dot(graph_name='Test', graph_type='graph')
|
||||
|
||||
self.assertEqual(g.get_type(), 'graph')
|
||||
|
||||
g = pydot.Dot(graph_name='Test', graph_type='digraph')
|
||||
g = pydotplus.Dot(graph_name='Test', graph_type='digraph')
|
||||
|
||||
self.assertEqual(g.get_type(), 'digraph')
|
||||
|
||||
def test_add_style(self):
|
||||
|
||||
node = pydot.Node('mynode')
|
||||
node = pydotplus.Node('mynode')
|
||||
node.add_style('abc')
|
||||
self.assertEqual(node.get_style(), 'abc')
|
||||
node.add_style('def')
|
||||
@ -68,27 +70,30 @@ class TestGraphAPI(unittest.TestCase):
|
||||
|
||||
def test_create_simple_graph_with_node(self):
|
||||
|
||||
g = pydot.Dot()
|
||||
g = pydotplus.Dot()
|
||||
g.set_type('digraph')
|
||||
node = pydot.Node('legend')
|
||||
node = pydotplus.Node('legend')
|
||||
node.set("shape", 'box')
|
||||
g.add_node(node)
|
||||
node.set('label', 'mine')
|
||||
|
||||
self.assertEqual(g.to_string(), 'digraph G {\nlegend [label=mine, shape=box];\n}\n')
|
||||
self.assertEqual(
|
||||
g.to_string(),
|
||||
'digraph G {\nlegend [label=mine, shape=box];\n}\n'
|
||||
)
|
||||
|
||||
def test_attribute_with_implicit_value(self):
|
||||
|
||||
d = 'digraph {\na -> b[label="hi", decorate];\n}'
|
||||
g = pydot.graph_from_dot_data(d)
|
||||
g = pydotplus.graph_from_dot_data(d)
|
||||
attrs = g.get_edges()[0].get_attributes()
|
||||
|
||||
self.assertEqual('decorate' in attrs, True)
|
||||
|
||||
def test_subgraphs(self):
|
||||
|
||||
g = pydot.Graph()
|
||||
s = pydot.Subgraph("foo")
|
||||
g = pydotplus.Graph()
|
||||
s = pydotplus.Subgraph("foo")
|
||||
|
||||
self.assertEqual(g.get_subgraphs(), [])
|
||||
self.assertEqual(g.get_subgraph_list(), [])
|
||||
@ -102,13 +107,13 @@ class TestGraphAPI(unittest.TestCase):
|
||||
|
||||
import pickle
|
||||
|
||||
g = pydot.Graph()
|
||||
s = pydot.Subgraph("foo")
|
||||
g = pydotplus.Graph()
|
||||
s = pydotplus.Subgraph("foo")
|
||||
g.add_subgraph(s)
|
||||
g.add_edge(pydot.Edge('A', 'B'))
|
||||
g.add_edge(pydot.Edge('A', 'C'))
|
||||
g.add_edge(pydot.Edge(('D', 'E')))
|
||||
g.add_node(pydot.Node('node!'))
|
||||
g.add_edge(pydotplus.Edge('A', 'B'))
|
||||
g.add_edge(pydotplus.Edge('A', 'C'))
|
||||
g.add_edge(pydotplus.Edge(('D', 'E')))
|
||||
g.add_node(pydotplus.Node('node!'))
|
||||
|
||||
self.assertEqual(type(pickle.dumps(g)), bytes)
|
||||
|
||||
@ -117,11 +122,11 @@ class TestGraphAPI(unittest.TestCase):
|
||||
node1 = '"aánñoöüé€"'
|
||||
node2 = '"îôø®çßΩ"'
|
||||
|
||||
g = pydot.Dot()
|
||||
g = pydotplus.Dot()
|
||||
g.set_charset('latin1')
|
||||
g.add_node(pydot.Node(node1))
|
||||
g.add_node(pydot.Node(node2))
|
||||
g.add_edge(pydot.Edge(node1, node2))
|
||||
g.add_node(pydotplus.Node(node1))
|
||||
g.add_node(pydotplus.Node(node2))
|
||||
g.add_edge(pydotplus.Edge(node1, node2))
|
||||
|
||||
self.assertEqual(g.get_node(node1)[0].get_name(), node1)
|
||||
self.assertEqual(g.get_node(node2)[0].get_name(), node2)
|
||||
@ -129,7 +134,7 @@ class TestGraphAPI(unittest.TestCase):
|
||||
self.assertEqual(g.get_edges()[0].get_source(), node1)
|
||||
self.assertEqual(g.get_edges()[0].get_destination(), node2)
|
||||
|
||||
g2 = pydot.graph_from_dot_data(g.to_string())
|
||||
g2 = pydotplus.graph_from_dot_data(g.to_string())
|
||||
|
||||
self.assertEqual(g2.get_node(node1)[0].get_name(), node1)
|
||||
self.assertEqual(g2.get_node(node2)[0].get_name(), node2)
|
||||
@ -152,7 +157,7 @@ class TestGraphAPI(unittest.TestCase):
|
||||
graph_data = f.read()
|
||||
f.close()
|
||||
|
||||
g = pydot.graph_from_dot_data(graph_data)
|
||||
g = pydotplus.graph_from_dot_data(graph_data)
|
||||
|
||||
g.set_shape_files(pngs)
|
||||
|
||||
@ -168,7 +173,7 @@ class TestGraphAPI(unittest.TestCase):
|
||||
|
||||
graph_data = 'graph A { a->b };\ngraph B {c->d}'
|
||||
|
||||
graphs = pydot.graph_from_dot_data(graph_data)
|
||||
graphs = pydotplus.graph_from_dot_data(graph_data)
|
||||
|
||||
self.assertEqual(len(graphs), 2)
|
||||
|
||||
@ -207,8 +212,8 @@ class TestGraphAPI(unittest.TestCase):
|
||||
# graph_data = f.read()
|
||||
# f.close()
|
||||
|
||||
#g = pydot.parse_from_dot_data(graph_data)
|
||||
g = pydot.graph_from_dot_file(filename)
|
||||
# g = pydotplus.parse_from_dot_data(graph_data)
|
||||
g = pydotplus.graph_from_dot_file(filename)
|
||||
|
||||
if not isinstance(g, list):
|
||||
g = [g]
|
||||
@ -231,7 +236,6 @@ class TestGraphAPI(unittest.TestCase):
|
||||
] # and fname.startswith('')]
|
||||
|
||||
for dot in dot_files:
|
||||
#print 'Processing: %s' % dot
|
||||
os.sys.stdout.write('#')
|
||||
os.sys.stdout.flush()
|
||||
|
||||
@ -242,7 +246,6 @@ class TestGraphAPI(unittest.TestCase):
|
||||
original_data_hexdigest = self._render_with_graphviz(fname)
|
||||
except Exception:
|
||||
print('Failed rendering BAD(%s)' % dot)
|
||||
#print 'Error:', str(excp)
|
||||
raise
|
||||
|
||||
if parsed_data_hexdigest != original_data_hexdigest:
|
||||
@ -254,7 +257,7 @@ class TestGraphAPI(unittest.TestCase):
|
||||
|
||||
self._reset_graphs()
|
||||
|
||||
self.graph_directed.add_node(pydot.Node(1))
|
||||
self.graph_directed.add_node(pydotplus.Node(1))
|
||||
|
||||
self.assertEqual(self.graph_directed.get_nodes()[0].get_name(), '1')
|
||||
|
||||
@ -262,23 +265,27 @@ class TestGraphAPI(unittest.TestCase):
|
||||
|
||||
self._reset_graphs()
|
||||
|
||||
self.graph_directed.add_node(pydot.Node('"node"'))
|
||||
self.graph_directed.add_node(pydotplus.Node('"node"'))
|
||||
|
||||
self.assertEqual(self.graph_directed.get_nodes()[0].get_name(), '"node"')
|
||||
self.assertEqual(
|
||||
self.graph_directed.get_nodes()[0].get_name(), '"node"'
|
||||
)
|
||||
|
||||
def test_quoted_node_id_to_string_no_attributes(self):
|
||||
|
||||
self._reset_graphs()
|
||||
|
||||
self.graph_directed.add_node(pydot.Node('"node"'))
|
||||
self.graph_directed.add_node(pydotplus.Node('"node"'))
|
||||
|
||||
self.assertEqual(self.graph_directed.get_nodes()[0].to_string(), '"node";')
|
||||
self.assertEqual(
|
||||
self.graph_directed.get_nodes()[0].to_string(), '"node";'
|
||||
)
|
||||
|
||||
def test_keyword_node_id(self):
|
||||
|
||||
self._reset_graphs()
|
||||
|
||||
self.graph_directed.add_node(pydot.Node('node'))
|
||||
self.graph_directed.add_node(pydotplus.Node('node'))
|
||||
|
||||
self.assertEqual(self.graph_directed.get_nodes()[0].get_name(), 'node')
|
||||
|
||||
@ -286,7 +293,7 @@ class TestGraphAPI(unittest.TestCase):
|
||||
|
||||
self._reset_graphs()
|
||||
|
||||
self.graph_directed.add_node(pydot.Node('node'))
|
||||
self.graph_directed.add_node(pydotplus.Node('node'))
|
||||
|
||||
self.assertEqual(self.graph_directed.get_nodes()[0].to_string(), '')
|
||||
|
||||
@ -294,9 +301,11 @@ class TestGraphAPI(unittest.TestCase):
|
||||
|
||||
self._reset_graphs()
|
||||
|
||||
self.graph_directed.add_node(pydot.Node('node', shape='box'))
|
||||
self.graph_directed.add_node(pydotplus.Node('node', shape='box'))
|
||||
|
||||
self.assertEqual(self.graph_directed.get_nodes()[0].to_string(), 'node [shape=box];')
|
||||
self.assertEqual(
|
||||
self.graph_directed.get_nodes()[0].to_string(), 'node [shape=box];'
|
||||
)
|
||||
|
||||
def test_names_of_a_thousand_nodes(self):
|
||||
|
||||
@ -306,18 +315,20 @@ class TestGraphAPI(unittest.TestCase):
|
||||
|
||||
for name in names:
|
||||
|
||||
self.graph_directed.add_node(pydot.Node(name, label=name))
|
||||
self.graph_directed.add_node(pydotplus.Node(name, label=name))
|
||||
|
||||
self.assertEqual(set([n.get_name() for n in self.graph_directed.get_nodes()]), names)
|
||||
self.assertEqual(
|
||||
set([n.get_name() for n in self.graph_directed.get_nodes()]), names
|
||||
)
|
||||
|
||||
def test_executable_not_found_exception(self):
|
||||
paths = {'dot': 'invalid_executable_path'}
|
||||
|
||||
graph = pydot.Dot('graphname', graph_type='digraph')
|
||||
graph = pydotplus.Dot('graphname', graph_type='digraph')
|
||||
|
||||
graph.set_graphviz_executables(paths)
|
||||
|
||||
self.assertRaises(pydot.InvocationException, graph.create)
|
||||
self.assertRaises(pydotplus.InvocationException, graph.create)
|
||||
|
||||
def test_graph_add_node_argument_type(self):
|
||||
|
||||
@ -342,9 +353,8 @@ class TestGraphAPI(unittest.TestCase):
|
||||
|
||||
def test_quoting(self):
|
||||
import string
|
||||
g = pydot.Dot()
|
||||
g.add_node(pydot.Node("test", label=string.printable))
|
||||
#print g.to_string()
|
||||
g = pydotplus.Dot()
|
||||
g.add_node(pydotplus.Node("test", label=string.printable))
|
||||
data = g.create(format='jpe')
|
||||
self.assertEqual(len(data) > 0, True)
|
||||
|
||||
|
42
tox.ini
Normal file
42
tox.ini
Normal file
@ -0,0 +1,42 @@
|
||||
[tox]
|
||||
envlist = py27, py34, coverage, docs
|
||||
|
||||
[testenv]
|
||||
deps=
|
||||
-rrequirements.txt
|
||||
flake8
|
||||
pytest
|
||||
setenv=
|
||||
PYTHONPATH=lib/
|
||||
commands=
|
||||
flake8
|
||||
py.test
|
||||
|
||||
[testenv:coverage]
|
||||
deps=
|
||||
-rrequirements.txt
|
||||
pytest-cov
|
||||
coveralls
|
||||
setenv=
|
||||
PYTHONPATH=lib/
|
||||
commands=
|
||||
py.test --cov pydotplus
|
||||
|
||||
[testenv:docs]
|
||||
basepython=python
|
||||
changedir=doc
|
||||
whitelist_externals=
|
||||
make
|
||||
dot
|
||||
deps=
|
||||
-rrequirements.txt
|
||||
sphinx
|
||||
sphinx_rtd_theme
|
||||
commands=
|
||||
make html
|
||||
|
||||
[flake8]
|
||||
exclude = ./doc/*,.tox/*,.git/*
|
||||
|
||||
[pytest]
|
||||
addopts = --doctest-modules --ignore=setup.py --ignore=doc/conf.py
|
Loading…
Reference in New Issue
Block a user