Description
Context: I'm using pytest 2.9.2, on Python 3.5, with a bunch of plugins (see outputs).
I have setup a tests module in my project with a test class similar to:
tests/test_project.py:
class TestProject:
def setup_method(self, method): pass
def teardown_method(self): pass # oops I forgot the method arg!
def test_project(self):
assert True
I ran it, and obtained the following traceback:
Test session starts (platform: linux, Python 3.5.1, pytest 2.9.2, pytest-sugar 0.7.1)
cachedir: .cache
rootdir: …, inifile:
plugins: cov-2.2.1, xdist-1.14, sugar-0.7.1, catchlog-1.2.2, datadir-ng-1.1.0
INTERNALERROR> Traceback (most recent call last):
INTERNALERROR> File "…/pytest-2.9.2-py3.5.egg/_pytest/main.py", line 94, in wrap_session
INTERNALERROR> session.exitstatus = doit(config, session) or 0
INTERNALERROR> File "…/pytest-2.9.2-py3.5.egg/_pytest/main.py", line 125, in _main
INTERNALERROR> config.hook.pytest_runtestloop(session=session)
INTERNALERROR> File "…/pytest-2.9.2-py3.5.egg/_pytest/vendored_packages/pluggy.py", line 724, in __call__
INTERNALERROR> return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)
INTERNALERROR> File "…/pytest-2.9.2-py3.5.egg/_pytest/vendored_packages/pluggy.py", line 338, in _hookexec
INTERNALERROR> return self._inner_hookexec(hook, methods, kwargs)
INTERNALERROR> File "…/pytest-2.9.2-py3.5.egg/_pytest/vendored_packages/pluggy.py", line 333, in <lambda>
INTERNALERROR> _MultiCall(methods, kwargs, hook.spec_opts).execute()
INTERNALERROR> File "…/pytest-2.9.2-py3.5.egg/_pytest/vendored_packages/pluggy.py", line 596, in execute
INTERNALERROR> res = hook_impl.function(*args)
INTERNALERROR> File "…/pytest-2.9.2-py3.5.egg/_pytest/main.py", line 150, in pytest_runtestloop
INTERNALERROR> item.config.hook.pytest_runtest_protocol(item=item, nextitem=nextitem)
INTERNALERROR> File "…/pytest-2.9.2-py3.5.egg/_pytest/vendored_packages/pluggy.py", line 724, in __call__
INTERNALERROR> return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)
INTERNALERROR> File "…/pytest-2.9.2-py3.5.egg/_pytest/vendored_packages/pluggy.py", line 338, in _hookexec
INTERNALERROR> return self._inner_hookexec(hook, methods, kwargs)
INTERNALERROR> File "…/pytest-2.9.2-py3.5.egg/_pytest/vendored_packages/pluggy.py", line 333, in <lambda>
INTERNALERROR> _MultiCall(methods, kwargs, hook.spec_opts).execute()
INTERNALERROR> File "…/pytest-2.9.2-py3.5.egg/_pytest/vendored_packages/pluggy.py", line 595, in execute
INTERNALERROR> return _wrapped_call(hook_impl.function(*args), self.execute)
INTERNALERROR> File "…/pytest-2.9.2-py3.5.egg/_pytest/vendored_packages/pluggy.py", line 253, in _wrapped_call
INTERNALERROR> return call_outcome.get_result()
INTERNALERROR> File "…/pytest-2.9.2-py3.5.egg/_pytest/vendored_packages/pluggy.py", line 278, in get_result
INTERNALERROR> raise ex[1].with_traceback(ex[2])
INTERNALERROR> File "…/pytest-2.9.2-py3.5.egg/_pytest/vendored_packages/pluggy.py", line 264, in __init__
INTERNALERROR> self.result = func()
INTERNALERROR> File "…/pytest-2.9.2-py3.5.egg/_pytest/vendored_packages/pluggy.py", line 596, in execute
INTERNALERROR> res = hook_impl.function(*args)
INTERNALERROR> File "…/pytest-2.9.2-py3.5.egg/_pytest/runner.py", line 66, in pytest_runtest_protocol
INTERNALERROR> runtestprotocol(item, nextitem=nextitem)
INTERNALERROR> File "…/pytest-2.9.2-py3.5.egg/_pytest/runner.py", line 78, in runtestprotocol
INTERNALERROR> nextitem=nextitem))
INTERNALERROR> File "…/pytest-2.9.2-py3.5.egg/_pytest/runner.py", line 122, in call_and_report
INTERNALERROR> report = hook.pytest_runtest_makereport(item=item, call=call)
INTERNALERROR> File "…/pytest-2.9.2-py3.5.egg/_pytest/vendored_packages/pluggy.py", line 724, in __call__
INTERNALERROR> return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)
INTERNALERROR> File "…/pytest-2.9.2-py3.5.egg/_pytest/vendored_packages/pluggy.py", line 338, in _hookexec
INTERNALERROR> return self._inner_hookexec(hook, methods, kwargs)
INTERNALERROR> File "…/pytest-2.9.2-py3.5.egg/_pytest/vendored_packages/pluggy.py", line 333, in <lambda>
INTERNALERROR> _MultiCall(methods, kwargs, hook.spec_opts).execute()
INTERNALERROR> File "…/pytest-2.9.2-py3.5.egg/_pytest/vendored_packages/pluggy.py", line 595, in execute
INTERNALERROR> return _wrapped_call(hook_impl.function(*args), self.execute)
INTERNALERROR> File "…/pytest-2.9.2-py3.5.egg/_pytest/vendored_packages/pluggy.py", line 249, in _wrapped_call
INTERNALERROR> wrap_controller.send(call_outcome)
INTERNALERROR> File "…/pytest-2.9.2-py3.5.egg/_pytest/skipping.py", line 226, in pytest_runtest_makereport
INTERNALERROR> rep = outcome.get_result()
INTERNALERROR> File "…/pytest-2.9.2-py3.5.egg/_pytest/vendored_packages/pluggy.py", line 278, in get_result
INTERNALERROR> raise ex[1].with_traceback(ex[2])
INTERNALERROR> File "…/pytest-2.9.2-py3.5.egg/_pytest/vendored_packages/pluggy.py", line 264, in __init__
INTERNALERROR> self.result = func()
INTERNALERROR> File "…/pytest-2.9.2-py3.5.egg/_pytest/vendored_packages/pluggy.py", line 596, in execute
INTERNALERROR> res = hook_impl.function(*args)
INTERNALERROR> File "…/pytest-2.9.2-py3.5.egg/_pytest/runner.py", line 232, in pytest_runtest_makereport
INTERNALERROR> style=item.config.option.tbstyle)
INTERNALERROR> File "…/pytest-2.9.2-py3.5.egg/_pytest/python.py", line 745, in _repr_failure_py
INTERNALERROR> style=style)
INTERNALERROR> File "…/pytest-2.9.2-py3.5.egg/_pytest/main.py", line 408, in _repr_failure_py
INTERNALERROR> style=style, tbfilter=tbfilter)
INTERNALERROR> File "…/pytest-2.9.2-py3.5.egg/_pytest/_code/code.py", line 418, in getrepr
INTERNALERROR> return fmt.repr_excinfo(self)
INTERNALERROR> File "…/pytest-2.9.2-py3.5.egg/_pytest/_code/code.py", line 599, in repr_excinfo
INTERNALERROR> reprcrash = excinfo._getreprcrash()
INTERNALERROR> File …/pytest-2.9.2-py3.5.egg/_pytest/_code/code.py", line 395, in _getreprcrash
INTERNALERROR> entry = self.traceback.getcrashentry()
INTERNALERROR> File "…/pytest-2.9.2-py3.5.egg/_pytest/_code/code.py", line 314, in getcrashentry
INTERNALERROR> return self[-1]
INTERNALERROR> File "…/pytest-2.9.2-py3.5.egg/_pytest/_code/code.py", line 289, in __getitem__
INTERNALERROR> val = super(Traceback, self).__getitem__(key)
INTERNALERROR> IndexError: list index out of range
Results (0.18s):
1 passed
I ran the test again with --fulltraceback
and had the traceback telling me that I'm wrong, with no issue (cf that gist).
After some discussion on #pylib
with @RonnyPfannschmidt, we figured out it's definitely the traceback pruning that's at fault: the exception is thrown within pytest
, so when pruning all pytest stuff, there's nothing left.
So as a solution we could do the following to avoid pruning if the last stack entry is from a file in the pytest lib:
at line 387
of _pytest/main.py
:
if self.config.option.fulltrace:
style="long"
else:
if not 'pytest' in excinfo.tb.tb_frame.f_code.co_filename:
self._prunetraceback(excinfo)
tbfilter = False # prunetraceback already does it
if style == "auto":
style = "long"
which will return the full stacktrace, as we're avoiding pruning it altogether. It's ok, but I'm not found of the test itself… it's a bit too Q&D.
or we could do the following version that prunes everything, showing only the last item of the stack, where there's useful information to debug:
at line 387
of _pytest/main.py
:
if self.config.option.fulltrace:
style="long"
else:
from ._code.code import Traceback
tb = Traceback([excinfo.traceback[-1]])
self._prunetraceback(excinfo)
if len(excinfo.traceback) == 0:
excinfo.traceback = tb
tbfilter = False # prunetraceback already does it
if style == "auto":
style = "long"
which gives:
―――――――――――――――――――――――――――――――――――――――――――――――― ERROR at teardown of TestProject.test_project ―――――――――――――――――――――――――――――――――――――――――――――――――
> self.addfinalizer(lambda: fin(self.obj))
E TypeError: teardown_method() takes 1 positional argument but 2 were given
var/eggs/pytest-2.9.2-py3.5.egg/_pytest/python.py:716: TypeError
tests/test_project.py
I'd be happy to submit a PR for solving this… But I guess it needs some discussion on whether either of my suggestions are good to solve the issue or not.