Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

When missing the method argument of teardown_method, getting INTERNALERROR #1604

Closed
guyzmo opened this issue Jun 11, 2016 · 2 comments
Closed

Comments

@guyzmo
Copy link
Contributor

guyzmo commented Jun 11, 2016

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.

@RonnyPfannschmidt
Copy link
Member

i consider keeping the last item a good idea for a starting point

a full pr would also need a test exposing the issue

i would propose at a later point to switch pruning with collapsing, so there would be "collapsed pytest internals" entry
but hats for a new issue

guyzmo added a commit to guyzmo/pytest that referenced this issue Jun 11, 2016
When the method argument is missing on teardown_method, the traceback is
100% internal to pytest, which with default options get pruned. Then
that traceback is empty, leading to a new exception as a traceback shall
not be empty.

This PR fixes that issue by pushing back the last stack on the
traceback, when the stacktrace is empty after pruning. Then the output
is still pruned, but gives meaningful information with the item where it
failed on the stack.

* fixes issue pytest-dev#1604

Signed-off-by: Guyzmo <guyzmo+github@m0g.net>
guyzmo added a commit to guyzmo/pytest that referenced this issue Jun 11, 2016
When the method argument is missing on teardown_method, the traceback is
100% internal to pytest, which with default options get pruned. Then
that traceback is empty, leading to a new exception as a traceback shall
not be empty.

This PR fixes that issue by pushing back the last stack on the
traceback, when the stacktrace is empty after pruning. Then the output
is still pruned, but gives meaningful information with the item where it
failed on the stack.

* fixes issue pytest-dev#1604

Signed-off-by: Guyzmo <guyzmo+github@m0g.net>
guyzmo added a commit to guyzmo/pytest that referenced this issue Jun 11, 2016
When the method argument is missing on teardown_method, the traceback is
100% internal to pytest, which with default options get pruned. Then
that traceback is empty, leading to a new exception as a traceback shall
not be empty.

This PR fixes that issue by pushing back the last stack on the
traceback, when the stacktrace is empty after pruning. Then the output
is still pruned, but gives meaningful information with the item where it
failed on the stack.

* fixes issue pytest-dev#1604

Signed-off-by: Guyzmo <guyzmo+github@m0g.net>
guyzmo added a commit to guyzmo/pytest that referenced this issue Jun 11, 2016
When the method argument is missing on teardown_method, the traceback is
100% internal to pytest, which with default options get pruned. Then
that traceback is empty, leading to a new exception as a traceback shall
not be empty.

This PR fixes that issue by pushing back the last stack on the
traceback, when the stacktrace is empty after pruning. Then the output
is still pruned, but gives meaningful information with the item where it
failed on the stack.

* fixes issue pytest-dev#1604

Signed-off-by: Guyzmo <guyzmo+github@m0g.net>
guyzmo added a commit to guyzmo/pytest that referenced this issue Jun 11, 2016
When the method argument is missing on teardown_method, the traceback is
100% internal to pytest, which with default options get pruned. Then
that traceback is empty, leading to a new exception as a traceback shall
not be empty.

This PR fixes that issue by pushing back the last stack on the
traceback, when the stacktrace is empty after pruning. Then the output
is still pruned, but gives meaningful information with the item where it
failed on the stack.

* fixes issue pytest-dev#1604

Signed-off-by: Guyzmo <guyzmo+github@m0g.net>
guyzmo added a commit to guyzmo/pytest that referenced this issue Jun 12, 2016
When the method argument is missing on teardown_method, the traceback is
100% internal to pytest, which with default options get pruned. Then
that traceback is empty, leading to a new exception as a traceback shall
not be empty.

This PR fixes that issue by pushing back the last stack on the
traceback, when the stacktrace is empty after pruning. Then the output
is still pruned, but gives meaningful information with the item where it
failed on the stack.

* fixes issue pytest-dev#1604

Signed-off-by: Guyzmo <guyzmo+github@m0g.net>
@nicoddemus
Copy link
Member

Fixed in current master.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants