nicoddemus / pytest-rich

pytest + rich integration (proof of concept)

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Failures in nested functions beyond one level raise `AssertionError`.

joshuadavidthomas opened this issue · comments

Failures in nested functions beyond one level raise AssertionError.

Basic reproduction:

def test_nested_failures():
    def inner():
        assert False
    inner()


def test_doubly_nested_failures():
    def inner():
        def inner_inner():
            assert False
        inner_inner()
    inner()


def test_triply_nested_failures():
    def inner():
        def inner_inner():
            def inner_inner_inner():
                assert False
            inner_inner_inner()
        inner_inner()
    inner()

The first function test_nested_failures fails as expected and prints the failure to the console, the other two raise an AssertionError and the test run quits.

Traceback

Traceback (most recent call last):
  File "/home/josh/.pyenv/versions/pytest-rich-3.10.6/bin/pytest", line 8, in <module>
    sys.exit(console_main())
  File "/home/josh/.pyenv/versions/3.10.6/envs/pytest-rich-3.10.6/lib/python3.10/site-packages/_pytest/config/__init__.py", line 190, in console_main
    code = main()
  File "/home/josh/.pyenv/versions/3.10.6/envs/pytest-rich-3.10.6/lib/python3.10/site-packages/_pytest/config/__init__.py", line 167, in main
    ret: Union[ExitCode, int] = config.hook.pytest_cmdline_main(
  File "/home/josh/.pyenv/versions/3.10.6/envs/pytest-rich-3.10.6/lib/python3.10/site-packages/pluggy/_hooks.py", line 265, in __call__
    return self._hookexec(self.name, self.get_hookimpls(), kwargs, firstresult)
  File "/home/josh/.pyenv/versions/3.10.6/envs/pytest-rich-3.10.6/lib/python3.10/site-packages/pluggy/_manager.py", line 80, in _hookexec
    return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
  File "/home/josh/.pyenv/versions/3.10.6/envs/pytest-rich-3.10.6/lib/python3.10/site-packages/pluggy/_callers.py", line 60, in _multicall
    return outcome.get_result()
  File "/home/josh/.pyenv/versions/3.10.6/envs/pytest-rich-3.10.6/lib/python3.10/site-packages/pluggy/_result.py", line 60, in get_result
    raise ex[1].with_traceback(ex[2])
  File "/home/josh/.pyenv/versions/3.10.6/envs/pytest-rich-3.10.6/lib/python3.10/site-packages/pluggy/_callers.py", line 39, in _multicall
    res = hook_impl.function(*args)
  File "/home/josh/.pyenv/versions/3.10.6/envs/pytest-rich-3.10.6/lib/python3.10/site-packages/_pytest/main.py", line 317, in pytest_cmdline_main
    return wrap_session(config, _main)
  File "/home/josh/.pyenv/versions/3.10.6/envs/pytest-rich-3.10.6/lib/python3.10/site-packages/_pytest/main.py", line 305, in wrap_session
    config.hook.pytest_sessionfinish(
  File "/home/josh/.pyenv/versions/3.10.6/envs/pytest-rich-3.10.6/lib/python3.10/site-packages/pluggy/_hooks.py", line 265, in __call__
    return self._hookexec(self.name, self.get_hookimpls(), kwargs, firstresult)
  File "/home/josh/.pyenv/versions/3.10.6/envs/pytest-rich-3.10.6/lib/python3.10/site-packages/pluggy/_manager.py", line 80, in _hookexec
    return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
  File "/home/josh/.pyenv/versions/3.10.6/envs/pytest-rich-3.10.6/lib/python3.10/site-packages/pluggy/_callers.py", line 60, in _multicall
    return outcome.get_result()
  File "/home/josh/.pyenv/versions/3.10.6/envs/pytest-rich-3.10.6/lib/python3.10/site-packages/pluggy/_result.py", line 60, in get_result
    raise ex[1].with_traceback(ex[2])
  File "/home/josh/.pyenv/versions/3.10.6/envs/pytest-rich-3.10.6/lib/python3.10/site-packages/pluggy/_callers.py", line 39, in _multicall
    res = hook_impl.function(*args)
  File "/home/josh/projects/pytest-rich/src/pytest_rich/terminal.py", line 213, in pytest_sessionfinish
    self.console.print(tb)
  File "/home/josh/.pyenv/versions/3.10.6/envs/pytest-rich-3.10.6/lib/python3.10/site-packages/rich/console.py", line 1694, in print
    extend(render(renderable, render_options))
  File "/home/josh/.pyenv/versions/3.10.6/envs/pytest-rich-3.10.6/lib/python3.10/site-packages/rich/console.py", line 1326, in render
    for render_output in iter_render:
  File "/home/josh/projects/pytest-rich/src/pytest_rich/traceback.py", line 84, in __rich_console__
    self._render_chain(self.chain, options),
  File "/home/josh/.pyenv/versions/3.10.6/envs/pytest-rich-3.10.6/lib/python3.10/site-packages/rich/console.py", line 510, in _replace
    return Group(*renderables, fit=fit)
  File "/home/josh/projects/pytest-rich/src/pytest_rich/traceback.py", line 211, in _render_chain
    assert entry.reprfuncargs is not None

Expected outcome

Handle the nested failures similar to the builtin pytest terminal reporter:

_______________________________________________ test_nested_failure ________________________________________________

    def test_nested_failure():
        def inner():
            assert False
>       inner()

tests/example/test_basic.py:53:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

    def inner():
>       assert False
E       assert False

tests/example/test_basic.py:51: AssertionError
___________________________________________ test_doubly_nested_failures ____________________________________________

    def test_doubly_nested_failures():
        def inner():
            def inner_inner():
                assert False
            inner_inner()
>       inner()

tests/example/test_basic.py:63:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
tests/example/test_basic.py:61: in inner
    inner_inner()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

    def inner_inner():
>       assert False
E       assert False

tests/example/test_basic.py:59: AssertionError
___________________________________________ test_triply_nested_failures ____________________________________________

    def test_triply_nested_failures():
        def inner():
            def inner_inner():
                def inner_inner_inner():
                    assert False
                inner_inner_inner()
            inner_inner()
>       inner()

tests/example/test_basic.py:76:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
tests/example/test_basic.py:74: in inner
    inner_inner()
tests/example/test_basic.py:72: in inner_inner
    inner_inner_inner()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

    def inner_inner_inner():
>       assert False
E       assert False

Problem lines:

assert entry.reprfuncargs is not None
args = get_args(entry.reprfuncargs)
if args:
yield args