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

Receive INTERNAL Error if no exception is thrown #29

Closed
Xyphenore opened this issue Apr 13, 2023 · 1 comment
Closed

Receive INTERNAL Error if no exception is thrown #29

Xyphenore opened this issue Apr 13, 2023 · 1 comment

Comments

@Xyphenore
Copy link

Hello, good plugin, I like it.
I have an INTERNAL ERROR with pytest 7.2.2 - 7.3.0 with the plugin pytest-raises.

If I decorate a test with '@pytest.mark.raises(exception=Exception)', where Exception can be any type of exception.
If this test finishes without raising an exception, pytest prints INTERNAL ERROR and stop the execution with code 3.

A basic example of broken test

import pytest

@pytest.mark.raises(exception=Exception)
def test_not_raises_exception() -> None:
    assert True
Traceback
INTERNALERROR> Traceback (most recent call last):
INTERNALERROR>   File "/home/xyf/test_raises/.venv/lib/python3.9/site-packages/_pytest/main.py", line 269, in wrap_session
INTERNALERROR>     session.exitstatus = doit(config, session) or 0
INTERNALERROR>   File "/home/xyf/test_raises/.venv/lib/python3.9/site-packages/_pytest/main.py", line 323, in _main
INTERNALERROR>     config.hook.pytest_runtestloop(session=session)
INTERNALERROR>   File "/home/xyf/test_raises/.venv/lib/python3.9/site-packages/pluggy/_hooks.py", line 265, in __call__
INTERNALERROR>     return self._hookexec(self.name, self.get_hookimpls(), kwargs, firstresult)
INTERNALERROR>   File "/home/xyf/test_raises/.venv/lib/python3.9/site-packages/pluggy/_manager.py", line 80, in _hookexec
INTERNALERROR>     return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
INTERNALERROR>   File "/home/xyf/test_raises/.venv/lib/python3.9/site-packages/pluggy/_callers.py", line 60, in _multicall
INTERNALERROR>     return outcome.get_result()
INTERNALERROR>   File "/home/xyf/test_raises/.venv/lib/python3.9/site-packages/pluggy/_result.py", line 60, in get_result
INTERNALERROR>     raise ex[1].with_traceback(ex[2])
INTERNALERROR>   File "/home/xyf/test_raises/.venv/lib/python3.9/site-packages/pluggy/_callers.py", line 39, in _multicall
INTERNALERROR>     res = hook_impl.function(*args)
INTERNALERROR>   File "/home/xyf/test_raises/.venv/lib/python3.9/site-packages/_pytest/main.py", line 348, in pytest_runtestloop
INTERNALERROR>     item.config.hook.pytest_runtest_protocol(item=item, nextitem=nextitem)
INTERNALERROR>   File "/home/xyf/test_raises/.venv/lib/python3.9/site-packages/pluggy/_hooks.py", line 265, in __call__
INTERNALERROR>     return self._hookexec(self.name, self.get_hookimpls(), kwargs, firstresult)
INTERNALERROR>   File "/home/xyf/test_raises/.venv/lib/python3.9/site-packages/pluggy/_manager.py", line 80, in _hookexec
INTERNALERROR>     return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
INTERNALERROR>   File "/home/xyf/test_raises/.venv/lib/python3.9/site-packages/pluggy/_callers.py", line 60, in _multicall
INTERNALERROR>     return outcome.get_result()
INTERNALERROR>   File "/home/xyf/test_raises/.venv/lib/python3.9/site-packages/pluggy/_result.py", line 60, in get_result
INTERNALERROR>     raise ex[1].with_traceback(ex[2])
INTERNALERROR>   File "/home/xyf/test_raises/.venv/lib/python3.9/site-packages/pluggy/_callers.py", line 39, in _multicall
INTERNALERROR>     res = hook_impl.function(*args)
INTERNALERROR>   File "/home/xyf/test_raises/.venv/lib/python3.9/site-packages/_pytest/runner.py", line 114, in pytest_runtest_protocol
INTERNALERROR>     runtestprotocol(item, nextitem=nextitem)
INTERNALERROR>   File "/home/xyf/test_raises/.venv/lib/python3.9/site-packages/_pytest/runner.py", line 133, in runtestprotocol
INTERNALERROR>     reports.append(call_and_report(item, "call", log))
INTERNALERROR>   File "/home/xyf/test_raises/.venv/lib/python3.9/site-packages/_pytest/runner.py", line 224, in call_and_report
INTERNALERROR>     report: TestReport = hook.pytest_runtest_makereport(item=item, call=call)
INTERNALERROR>   File "/home/xyf/test_raises/.venv/lib/python3.9/site-packages/pluggy/_hooks.py", line 265, in __call__
INTERNALERROR>     return self._hookexec(self.name, self.get_hookimpls(), kwargs, firstresult)
INTERNALERROR>   File "/home/xyf/test_raises/.venv/lib/python3.9/site-packages/pluggy/_manager.py", line 80, in _hookexec
INTERNALERROR>     return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
INTERNALERROR>   File "/home/xyf/test_raises/.venv/lib/python3.9/site-packages/pluggy/_callers.py", line 55, in _multicall
INTERNALERROR>     gen.send(outcome)
INTERNALERROR>   File "/home/xyf/test_raises/.venv/lib/python3.9/site-packages/_pytest/skipping.py", line 266, in pytest_runtest_makereport
INTERNALERROR>     rep = outcome.get_result()
INTERNALERROR>   File "/home/xyf/test_raises/.venv/lib/python3.9/site-packages/pluggy/_result.py", line 60, in get_result
INTERNALERROR>     raise ex[1].with_traceback(ex[2])
INTERNALERROR>   File "/home/xyf/test_raises/.venv/lib/python3.9/site-packages/pluggy/_callers.py", line 39, in _multicall
INTERNALERROR>     res = hook_impl.function(*args)
INTERNALERROR>   File "/home/xyf/test_raises/.venv/lib/python3.9/site-packages/_pytest/runner.py", line 368, in pytest_runtest_makereport
INTERNALERROR>     return TestReport.from_item_and_call(item, call)
INTERNALERROR>   File "/home/xyf/test_raises/.venv/lib/python3.9/site-packages/_pytest/reports.py", line 363, in from_item_and_call
INTERNALERROR>     longrepr = item.repr_failure(excinfo)
INTERNALERROR>   File "/home/xyf/test_raises/.venv/lib/python3.9/site-packages/_pytest/python.py", line 1833, in repr_failure
INTERNALERROR>     return self._repr_failure_py(excinfo, style=style)
INTERNALERROR>   File "/home/xyf/test_raises/.venv/lib/python3.9/site-packages/_pytest/nodes.py", line 484, in _repr_failure_py
INTERNALERROR>     return excinfo.getrepr(
INTERNALERROR>   File "/home/xyf/test_raises/.venv/lib/python3.9/site-packages/_pytest/_code/code.py", line 671, in getrepr
INTERNALERROR>     return fmt.repr_excinfo(self)
INTERNALERROR>   File "/home/xyf/test_raises/.venv/lib/python3.9/site-packages/_pytest/_code/code.py", line 987, in repr_excinfo
INTERNALERROR>     return ExceptionChainRepr(repr_chain)
INTERNALERROR>   File "/home/xyf/test_raises/.venv/lib/python3.9/site-packages/_pytest/_code/code.py", line 1039, in __init__
INTERNALERROR>     reprtraceback=chain[-1][0],
INTERNALERROR> IndexError: list index out of range

Process finished with exit code 3

The problem is present only if no exception is thrown.
Then the exception raised line 84 'raise ExceptionClass(failure_message)' in '_pytest_raises_validation' is hidden because '__tracebackhide__' is True.
If in the function '_pytest_fail_by_mark_or_set_excinfo' '__tracebackhide__' is set to False, pytest does not stop the execution, but the traceback is bad.

Bad Traceback
item = <Function test_not_raises_exception>
outcome = <pluggy._result._Result object at 0x7fc688f3e4f0>
marker_name = 'raises'
ExceptionClass = <class 'pytest_raises.pytest_raises.ExpectedException'>
failure_message = "Expected exception <class 'Exception'>, but it did not raise"
traceback = None

    def _pytest_fail_by_mark_or_set_excinfo(item, outcome, marker_name, ExceptionClass, failure_message, traceback):
        """
        Defer a test failure to a later stage, or set ``excinfo`` of ``outcome``, depending
        on ``marker_name``.  This function should only be called for test items that have
        failed -- the end result of calling this function for *any* ``item`` / ``outcome``
        is that the test will fail.
    
        .. warning::
    
            **This is a "private" function not intended to be called directly by external projects!**
    
        Depending on the stage at which this function is called, one of two actions will
        be performed:
    
        1. ``marker_name='setup_raises'``: a "secret" marker will be added to ``item``
           indicating that the test failed.  This marker is then checked at a later stage
           when it is safe to fail.  See documentation for :func:`_pytest_raises_validation`
           for more information.
        2. ``marker_name='raises'``: the ``outcome.excinfo`` will be populated with an
           exception traceback that will eventually (through ``pytest``) mark the test as
           failed.
    
        **Parameters**
    
        ``item``
            The ``pytest`` test item, e.g., what is supplied to
            ``pytest_runtest_setup(item)`` or ``pytest_runtest_call(item)``.
    
        ``outcome``
            The ``pytest`` test outcome for the ``@pytest.hookimpl(hookwrapper=True)`` hook
            wrappers, where ``outcome = yield``.
    
        ``marker_name``
            The string marker name.  Values are **assumed** to be ``'setup_raises'`` or
            ``'raises'`` **only**.
    
            - ``'setup_raises'``: call originates from ``pytest_runtest_setup`` hook wrapper.
            - ``'raises'``: call originates from ``pytest_runtest_call`` hook wrapper.
    
        ``ExceptionClass``
            The exception class to re-raise.  Expected to be :class:`ExpectedException` or
            :class:`ExpectedMessage`, but not strictly required.
    
        ``failure_message``
            The string failure message to mark with or re-raise, depending on the value
            of ``marker_name``.
    
        ``traceback``
            The traceback information if available, ``None`` otherwise.
        """
        # pylint: disable=unused-variable
        __tracebackhide__ = False
        if marker_name == 'setup_raises':
            # In the later stage when `fail` is called, it is nice to "simulate" an
            # exception by putting the expected exception class's name as a prefix.
            failure_message = '{}: {}'.format(ExceptionClass.__name__, failure_message)
            item.add_marker(pytest.mark.setup_raises_expected_exc_or_message_not_found(failure_message))
        else:  # marker_name == 'raises'
            # Avoid "while handling exception another exception occurred" scenarios.
            if issubclass(ExceptionClass, PytestRaisesUsageError):
                failure_message = '{}: {}'.format(ExceptionClass.__name__, failure_message)
                pytest.fail(failure_message, pytrace=False)
            else:
                try:
>                   raise ExceptionClass(failure_message)
E                   pytest_raises.pytest_raises.ExpectedException: Expected exception <class 'Exception'>, but it did not raise

.venv/lib/python3.9/site-packages/pytest_raises/pytest_raises.py:84: ExpectedException

I don't know how to fix this problem.

I have installed this dependencies:
Python = 3.9.5
coverage = "^7.1.0"
pytest = "<8.0.0"
pytest-asyncio = "<1.0.0"
pytest-cov = "^4.0.0"
pytest-raises = "<1.0.0"
pytest-xdist = {extras = ["psutil"], version = "^3.2.1"}
pytest-rich = "^0.1.1"
pytest-timer = "^0.0.11"
attrs = "^22.2.0"

@Xyphenore
Copy link
Author

It's a pytest bug pytest-dev/pytest#10903.
Fixed in pytest 7.3.1 https://github.com/pytest-dev/pytest/releases/tag/7.3.1

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

1 participant