So my last iteration is here. It felt unintuitive to use
pycollect_makeitem, but seems to be the solution, after all. If you see any
flaws I would be grateful to hear about them.
Tibor
@pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_pycollect_makeitem(self, collector, name, obj):
makeitem_result = yield
items = makeitem_result.get_result()
if items:
try:
self.raw_nodeids.extend([item.nodeid for item in items if
isinstance(item, pytest.Item)])
except TypeError: # 'Class' object is not iterable
pass
The whole test script:
import pytest
pytest_plugins = "pytester"
def test_pytest_assumption(testdir):
testdir.makepyfile(__init__="")
testdir.makepyfile(test_a="""
import pytest
class Test1():
@pytest.mark.parametrize('a', [1, 2])
def test_1(self, a):
pass
def test_2(self):
pass
""")
class Plugin:
def __init__(self):
self.raw_nodeids = []
@pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_pycollect_makeitem(self, collector, name, obj):
makeitem_result = yield
items = makeitem_result.get_result()
if items:
try:
self.raw_nodeids.extend([item.nodeid for item in
items if isinstance(item, pytest.Item)])
except TypeError: # 'Class' object is not iterable
pass
plugin = Plugin()
result = testdir.runpytest_inprocess("test_a.py::Test1::test_2",
plugins=[plugin])
assert plugin.raw_nodeids == ['test_a.py::Test1::test_1[1]',
'test_a.py::Test1::test_1[2]',
'test_a.py::Test1::test_2']
result.assert_outcomes(1, 0, 0)
On Sun, Nov 3, 2019 at 12:35 AM Tibor Arpas <[email protected]> wrote:
> So my method doesn't work when Packages are involved. package.collect()
> returns the necessary nodes only once (it thinks the second execution
> encountered duplicates, so it returns empty tuple). So my gen_nodeids
> breaks normal collection. The bug or feature is demonstrated below. Is
> there a better way, please? If I invoke runpytest with "--keepduplicates"
> the test passes. Maybe I could use package._collectfile(...,
> handle_dupes=False) but that is non-API territory so I didn't investigate
> further yet.
>
> Tibor
>
> This fails with
> /Users/tibor/tmonworkspace/testmon.io/test/test_collect.py:33: in
> pytest_collect_file
> assert nodeids == nodeids2
> E AssertionError: assert ['test_a.py::Test1::test_1',
> 'test_a.py::Test1::test_2'] == []
>
> import pytest
>
> pytest_plugins = "pytester"
>
>
> def test_pytest_assumption(testdir):
> testdir.makepyfile(__init__="")
>
> testdir.makepyfile(test_a="""
> class Test1():
> def test_1(self):
> pass
> def test_2(self):
> pass
> """)
>
> class Plugin:
>
> @pytest.hookimpl(hookwrapper=True)
> def pytest_collect_file(self, path, parent):
> def gen_nodeids(nodes):
> for node in nodes:
> if isinstance(node, pytest.Item):
> yield node.nodeid
> else:
> yield from gen_nodeids(node.collect())
>
>
> collect_file_result = yield
> nodeids = list(gen_nodeids(collect_file_result.get_result()))
> nodeids2 = list(gen_nodeids(collect_file_result.get_result()))
> assert len(nodeids) == 2
> assert nodeids == nodeids2
>
> result = testdir.runpytest_inprocess("-v", "test_a.py::Test1::test_1",
> plugins=[Plugin()])
> result.assert_outcomes(1, 0, 0)
>
>
>
> On Sat, Nov 2, 2019 at 9:52 PM Tibor Arpas <[email protected]> wrote:
>
>> Hi,
>>
>> For pytest-testmon plugin I need to extract all node ids which exist in a
>> python file (after parametrization). Initially, I thought
>> pytest_collection_modifyitems used as a hookwrapper would have all the
>> node_ids in all the files (which would be ideal for me). It turns out if
>> you call pytest test_a.py::test_1 , pytest_collection_modifyitems only gets
>> test_a.py::test_1 (but no other nodes which might be in test_a.py).
>> pytest_pycollect_makemodule sounds like the pretty low-level hook which
>> should get all I need. However, it gets a hierarchy, which I have to
>> manually flatten. My gen_nodeids bellow looks like a code that definitely
>> lives somewhere in pytest. What is the optimal and most forward-compatible
>> way to get the list, please? Below is what I came up with so far (and it
>> seems to work).
>>
>> I would be glad to get any comments or pointers.
>>
>> Best,
>> Tibor
>> twitter: tibor_a
>>
>> import pytest
>>
>> pytest_plugins = "pytester"
>>
>>
>> def test_pytest_assumption(testdir):
>> testdir.makepyfile(test_a="""
>> class Test1():
>> def test_1(self):
>> pass
>> """)
>>
>> class Plugin:
>> @pytest.hookimpl(hookwrapper=True)
>> def pytest_pycollect_makemodule(self, path, parent):
>> def gen_nodeids(nodes):
>> for node in nodes:
>> if isinstance(node, pytest.Function):
>> yield node.nodeid
>> else:
>> yield from gen_nodeids(node.collect())
>>
>> make_module_result = yield
>> nodeids =
>> list(gen_nodeids(make_module_result.get_result().collect()))
>> assert nodeids == ['test_a.py::Test1::test_1']
>>
>> result = testdir.runpytest_inprocess("--testmon-dev", plugins=[Plugin()])
>> result.assert_outcomes(1, 0, 0)
>>
>>
_______________________________________________
pytest-dev mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pytest-dev