Skip to content

Commit 021a564

Browse files
authored
Merge pull request #3 from fruch/master
Adding pydot --fixture-graph
2 parents af57cb6 + 33e4382 commit 021a564

File tree

7 files changed

+153
-6
lines changed

7 files changed

+153
-6
lines changed

.travis.yml

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
language: python
2+
python:
3+
- "2.7"
4+
- "3.4"
5+
- "3.5"
6+
- "3.6"
7+
- "nightly"
28
# command to install dependencies
39
install:
410
- pip install python-coveralls virtualenv
511
# # command to run tests
6-
script: python setup.py test
7-
after_success:
12+
script:
813
- pip install -r requirements-testing.txt -e .
914
- py.test --cov=pytest_fixture_tools --cov-report=term-missing tests
1015
- coveralls

README.rst

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ Installation
2222
Usage
2323
-----
2424

25+
show-fixture-duplicates
26+
***********************
27+
2528
If you have already installed ``pytest-fixture-tools`` plugin then you can use one of its commands.
2629

2730
``--show-fixture-duplicates`` - will collect all fixtures and print you a list of duplicates for each fixture.
@@ -47,6 +50,55 @@ Output can look like this:
4750
tests/fixtures/order.py:30
4851
tests/unit/api/conftest.py:261
4952

53+
fixture-graph
54+
*************
55+
56+
You can generate the usage fixture graph like that:
57+
58+
.. sourcecode:: bash
59+
60+
# on windows gitbash as example
61+
export PATH=$PATH:/c/Program\ Files\ \(x86\)/Graphviz2.38/bin/
62+
pytest --fixture-graph -s
63+
64+
# or you can select the output direcotry like that:
65+
pytest --fixture-graph --fixture-graph-output-dir=./test_output
66+
67+
# you can also change the output type of the graphs (any of graphvis supported outputs types):
68+
pytest --fixture-graph --fixture-graph-type=jpg
69+
70+
The output would be like that:
71+
72+
.. sourcecode::
73+
74+
============================= test session starts =============================
75+
platform win32 -- Python 2.7.10, pytest-3.3.1, py-1.5.2, pluggy-0.6.0
76+
rootdir: C:\Users\ifruchte\Projects\pytest-fixture-tools, inifile: tox.ini
77+
plugins: pep8-1.0.6, cov-2.5.1, fixture-tools-1.0.0
78+
collected 7 items
79+
80+
pytest_fixture_tools\__init__.py . [ 14%]
81+
pytest_fixture_tools\plugin.py . [ 28%]
82+
tests\__init__.py . [ 42%]
83+
tests\conftest.py . [ 57%]
84+
tests\test_fixture_duplicates.py .
85+
-------------------------------- fixture-graph --------------------------------
86+
created artifacts/fixture-graph-tests-test_fixture_duplicates.py__test_there_are_fixture_duplicates.png.
87+
============================= test session starts =============================
88+
platform win32 -- Python 2.7.10, pytest-3.3.1, py-1.5.2, pluggy-0.6.0
89+
rootdir: c:\users\ifruchte\appdata\local\temp\pytest-of-ifruchte\pytest-445\test_there_are_not_fixture_duplicates0, inifile:
90+
plugins: pep8-1.0.6, cov-2.5.1, fixture-tools-1.0.0
91+
collected 2 items
92+
93+
======================== no tests ran in 0.06 seconds =========================
94+
.s [100%]
95+
96+
===================== 6 passed, 1 skipped in 0.29 seconds =====================
97+
98+
Final output, that can help with tests that depend on large amount of fixtures:
99+
100+
.. image:: imgs/graph_example.png
101+
:alt: alternate text
50102

51103
Contact
52104
-------

imgs/graph_example.png

17.5 KB
Loading

pytest_fixture_tools/plugin.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,28 @@
11
"""Pytest fixture tools plugin."""
22

33
import py
4+
import os
5+
import errno
46

57
from _pytest.python import getlocation
68
from collections import defaultdict
79

10+
import pydot
11+
812
tw = py.io.TerminalWriter()
913
verbose = 1
1014

1115

16+
def mkdir_recursive(path):
17+
try:
18+
os.makedirs(path)
19+
except OSError as exc:
20+
if exc.errno == errno.EEXIST and os.path.isdir(path):
21+
pass
22+
else:
23+
raise
24+
25+
1226
def pytest_addoption(parser):
1327
"""Add commandline options show-fixture-duplicates and fixture."""
1428
group = parser.getgroup("general")
@@ -19,6 +33,16 @@ def pytest_addoption(parser):
1933
action="store", type=str, dest="fixture_name", default='',
2034
help="Name of specific fixture for which you want to get duplicates")
2135

36+
group.addoption('--fixture-graph',
37+
action="store_true", dest="fixture_graph", default=False,
38+
help="create .dot fixture graph for each test")
39+
group.addoption('--fixture-graph-output-dir',
40+
action="store_true", dest="fixture_graph_output_dir", default="artifacts",
41+
help="select the location for the output of fixture graph. defaults to 'artifacts'")
42+
group.addoption('--fixture-graph-output-type',
43+
action="store_true", dest="fixture_graph_output_type", default="png",
44+
help="select the type of the output for the fixture graph. defaults to 'png'")
45+
2246

2347
def pytest_cmdline_main(config):
2448
"""Check show_fixture_duplicates option to show fixture duplicates."""
@@ -93,3 +117,40 @@ def _show_fixture_duplicates_main(config, session):
93117
for argname, fixtures in available:
94118
print_duplicates(argname, fixtures, previous_argname)
95119
previous_argname = argname
120+
121+
122+
def pytest_runtest_setup(item):
123+
if item.config.option.fixture_graph and hasattr(item, "_fixtureinfo"):
124+
# fixtures came from function parameters names
125+
data = dict()
126+
data['func_args'] = item._fixtureinfo.argnames, 'red'
127+
for fixture_name, fixture_data in list(item._fixtureinfo.name2fixturedefs.items()):
128+
129+
color = 'green'
130+
data[fixture_name] = fixture_data[0].argnames, color
131+
132+
graph = pydot.Dot(graph_type='digraph')
133+
134+
for name, depended_list in list(data.items()):
135+
depended_list, color = depended_list
136+
137+
node = pydot.Node(name, style="filled", fillcolor=color)
138+
graph.add_node(node)
139+
for i in depended_list:
140+
edge = pydot.Edge(node, i)
141+
graph.add_edge(edge)
142+
143+
log_dir = item.config.option.fixture_graph_output_dir
144+
output_type = item.config.option.fixture_graph_output_type
145+
mkdir_recursive(log_dir)
146+
filename = "{0}/fixture-graph-{1}".format(log_dir, item._nodeid.replace(":", "_").replace("/", "-"))
147+
tw.line()
148+
tw.sep("-", "fixture-graph")
149+
try:
150+
graph.write("{}.{}".format(filename, output_type), format=output_type)
151+
tw.line("created {}.{}.".format(filename, output_type))
152+
except Exception:
153+
tw.line("graphvis wasn't found in PATH")
154+
graph.write(filename + ".dot")
155+
tw.line("created {}.dot.".format(filename))
156+
tw.line("You can convert it to a PNG using:\n\t'dot -Tpng {0}.dot -o {0}.png'".format(filename))

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def run_tests(self):
5252
] + [('Programming Language :: Python :: %s' % x) for x in '2.6 2.7 3.0 3.1 3.2 3.3'.split()],
5353
cmdclass={'test': ToxTestCommand},
5454
install_requires=[
55-
'pytest',
55+
'pytest', 'pydot'
5656
],
5757
# the following makes a plugin available to py.test
5858
entry_points={

tests/test_fixtrue_graph.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import py
2+
3+
4+
def test_fixture_graph_created(testdir):
5+
"""Check that --fixture-graph will create the graph .dot file"""
6+
sub1 = testdir.mkpydir("sub1")
7+
sub2 = testdir.mkpydir("sub1/sub2")
8+
sub1.join("conftest.py").write(py.code.Source("""
9+
import pytest
10+
11+
@pytest.fixture
12+
def arg1(request):
13+
pass
14+
"""))
15+
sub2.join("conftest.py").write(py.code.Source("""
16+
import pytest
17+
18+
@pytest.fixture
19+
def arg1(request):
20+
pass
21+
"""))
22+
sub1.join("test_in_sub1.py").write("def test_1(arg1): pass")
23+
sub2.join("test_in_sub2.py").write("def test_2(arg1): pass")
24+
25+
result = testdir.runpytest_subprocess('--fixture-graph', '-s')
26+
27+
result.stdout.fnmatch_lines("created artifacts/fixture-graph-sub1-test_in_sub1.py__test_1.dot.")
28+
result.stdout.fnmatch_lines('created artifacts/fixture-graph-sub1-sub2-test_in_sub2.py__test_2.dot.')

tests/test_fixture_duplicates.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"""Test for checking getting of duplicates."""
22
import py
3+
import pytest
34

45

56
def test_there_are_not_fixture_duplicates(testdir):
@@ -49,7 +50,7 @@ def arg1(request):
4950
sub1.join("test_in_sub1.py").write("def test_1(arg1): pass")
5051
sub2.join("test_in_sub2.py").write("def test_2(arg1): pass")
5152

52-
result = testdir.runpytest('--show-fixture-duplicates')
53+
result = testdir.runpytest_subprocess('--show-fixture-duplicates', '-s')
5354

54-
assert result.stdout.lines.count('sub1/conftest.py:5') == 1
55-
assert result.stdout.lines.count('sub1/sub2/conftest.py:5') == 1
55+
result.stdout.fnmatch_lines('sub1/conftest.py:5')
56+
result.stdout.fnmatch_lines('sub1/sub2/conftest.py:5')

0 commit comments

Comments
 (0)