I have a plugin that implements the following hooks:
def pytest_runtest_setup(item):
item.config.bla = Bla()
def pytest_runtest_teardown(item):
item.config.bla.do_bla()
item.config.bla = None
All works fine until some tests start to throw AttributeError: 'NoneType' object has no attribute 'do_bla'
and indeed, item.config.bla
is None
This happens in tests which I marked as
@pytest.mark.skip(reason='bla bla')
def test_bla():
pass
I tried ipdb
-ing the setup hook - but it is not called, while the teardown is. Does it make sense that setups are not called for skip tests while teardowns are?
I can wrap my teardown with try, except
but I want to verify the root cause...
The problem seems to be that the pytest_runtest_setup
hook is implemented by several components in pytest itself, one being the skipping
module (_pytest/skipping.py
).
The implementation does something like this:
@hookimpl(tryfirst=True)
def pytest_runtest_setup(item):
...
for skip_info in item.iter_markers(name="skip"):
item._store[skipped_by_mark_key] = True
if "reason" in skip_info.kwargs:
skip(skip_info.kwargs["reason"])
elif skip_info.args:
skip(skip_info.args[0])
else:
skip("unconditional skip")
e.g. if it finds a skip
mark, it raises Skipped()
(which is basically all that skip
does), which is caught only after any pre-test and test hooks would be executed.
I don't know if this intentional, but you obviously have to expect this behavior (which you can easily do in your case by catching the AttributeError
, as you wrote).