fixtures: fix tracebacks for higher-scoped failed fixtures getting longer and longer
Fix #12204.
This commit is contained in:
parent
127a372928
commit
0b91d5e3e8
|
@ -0,0 +1,4 @@
|
|||
Fix a regression in pytest 8.0 where tracebacks get longer and longer when multiple tests fail due to a shared higher-scope fixture which raised.
|
||||
|
||||
The fix necessitated internal changes which may affect some plugins:
|
||||
- ``FixtureDef.cached_result[2]`` is now a tuple ``(exc, tb)`` instead of ``exc``.
|
|
@ -8,6 +8,7 @@ import inspect
|
|||
import os
|
||||
from pathlib import Path
|
||||
import sys
|
||||
import types
|
||||
from typing import AbstractSet
|
||||
from typing import Any
|
||||
from typing import Callable
|
||||
|
@ -104,8 +105,8 @@ _FixtureCachedResult = Union[
|
|||
None,
|
||||
# Cache key.
|
||||
object,
|
||||
# Exception if raised.
|
||||
BaseException,
|
||||
# The exception and the original traceback.
|
||||
Tuple[BaseException, Optional[types.TracebackType]],
|
||||
],
|
||||
]
|
||||
|
||||
|
@ -1049,8 +1050,8 @@ class FixtureDef(Generic[FixtureValue]):
|
|||
# numpy arrays (#6497).
|
||||
if my_cache_key is cache_key:
|
||||
if self.cached_result[2] is not None:
|
||||
exc = self.cached_result[2]
|
||||
raise exc
|
||||
exc, exc_tb = self.cached_result[2]
|
||||
raise exc.with_traceback(exc_tb)
|
||||
else:
|
||||
result = self.cached_result[0]
|
||||
return result
|
||||
|
@ -1126,7 +1127,7 @@ def pytest_fixture_setup(
|
|||
# Don't show the fixture as the skip location, as then the user
|
||||
# wouldn't know which test skipped.
|
||||
e._use_item_location = True
|
||||
fixturedef.cached_result = (None, my_cache_key, e)
|
||||
fixturedef.cached_result = (None, my_cache_key, (e, e.__traceback__))
|
||||
raise
|
||||
fixturedef.cached_result = (result, my_cache_key, None)
|
||||
return result
|
||||
|
|
|
@ -3397,6 +3397,28 @@ class TestErrors:
|
|||
["*def gen(qwe123):*", "*fixture*qwe123*not found*", "*1 error*"]
|
||||
)
|
||||
|
||||
def test_cached_exception_doesnt_get_longer(self, pytester: Pytester) -> None:
|
||||
"""Regression test for #12204."""
|
||||
pytester.makepyfile(
|
||||
"""
|
||||
import pytest
|
||||
@pytest.fixture(scope="session")
|
||||
def bad(): 1 / 0
|
||||
|
||||
def test_1(bad): pass
|
||||
def test_2(bad): pass
|
||||
def test_3(bad): pass
|
||||
"""
|
||||
)
|
||||
|
||||
result = pytester.runpytest_inprocess("--tb=native")
|
||||
assert result.ret == ExitCode.TESTS_FAILED
|
||||
failures = result.reprec.getfailures() # type: ignore[attr-defined]
|
||||
assert len(failures) == 3
|
||||
lines1 = failures[1].longrepr.reprtraceback.reprentries[0].lines
|
||||
lines2 = failures[2].longrepr.reprtraceback.reprentries[0].lines
|
||||
assert len(lines1) == len(lines2)
|
||||
|
||||
|
||||
class TestShowFixtures:
|
||||
def test_funcarg_compat(self, pytester: Pytester) -> None:
|
||||
|
|
Loading…
Reference in New Issue