Skip to content

Commit

Permalink
Merge pull request #504 from bluetech/reraise
Browse files Browse the repository at this point in the history
result: keep original traceback and reraise with it
  • Loading branch information
bluetech committed Apr 30, 2024
2 parents 313eace + 93ac1e9 commit 56085d7
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 4 deletions.
1 change: 1 addition & 0 deletions changelog/504.bugfix.rst
@@ -0,0 +1 @@
Fix a regression in pluggy 1.1.0 where using :func:`result.get_result() <pluggy.Result.get_result>` on the same failed :class:`~pluggy.Result` causes the exception's traceback to get longer and longer.
2 changes: 1 addition & 1 deletion src/pluggy/_callers.py
Expand Up @@ -136,7 +136,7 @@ def _multicall(
_raise_wrapfail(teardown, "has second yield") # type: ignore[arg-type]

if exception is not None:
raise exception.with_traceback(exception.__traceback__)
raise exception
else:
return result

Expand Down
11 changes: 8 additions & 3 deletions src/pluggy/_result.py
Expand Up @@ -28,7 +28,7 @@ class Result(Generic[ResultType]):
"""An object used to inspect and set the result in a :ref:`hook wrapper
<hookwrappers>`."""

__slots__ = ("_result", "_exception")
__slots__ = ("_result", "_exception", "_traceback")

def __init__(
self,
Expand All @@ -38,6 +38,8 @@ def __init__(
""":meta private:"""
self._result = result
self._exception = exception
# Exception __traceback__ is mutable, this keeps the original.
self._traceback = exception.__traceback__ if exception is not None else None

@property
def excinfo(self) -> _ExcInfo | None:
Expand All @@ -46,7 +48,7 @@ def excinfo(self) -> _ExcInfo | None:
if exc is None:
return None
else:
return (type(exc), exc, exc.__traceback__)
return (type(exc), exc, self._traceback)

@property
def exception(self) -> BaseException | None:
Expand Down Expand Up @@ -75,6 +77,7 @@ def force_result(self, result: ResultType) -> None:
"""
self._result = result
self._exception = None
self._traceback = None

def force_exception(self, exception: BaseException) -> None:
"""Force the result to fail with ``exception``.
Expand All @@ -85,6 +88,7 @@ def force_exception(self, exception: BaseException) -> None:
"""
self._result = None
self._exception = exception
self._traceback = exception.__traceback__ if exception is not None else None

def get_result(self) -> ResultType:
"""Get the result(s) for this hook call.
Expand All @@ -94,10 +98,11 @@ def get_result(self) -> ResultType:
"""
__tracebackhide__ = True
exc = self._exception
tb = self._traceback
if exc is None:
return cast(ResultType, self._result)
else:
raise exc.with_traceback(exc.__traceback__)
raise exc.with_traceback(tb)


# Historical name (pluggy<=1.2), kept for backward compatibility.
Expand Down
27 changes: 27 additions & 0 deletions testing/test_result.py
@@ -0,0 +1,27 @@
import traceback

from pluggy import Result


def test_exceptions_traceback_doesnt_get_longer_and_longer() -> None:
def bad() -> None:
1 / 0

result = Result.from_call(bad)

try:
result.get_result()
except Exception as exc:
tb1 = traceback.extract_tb(exc.__traceback__)

try:
result.get_result()
except Exception as exc:
tb2 = traceback.extract_tb(exc.__traceback__)

try:
result.get_result()
except Exception as exc:
tb3 = traceback.extract_tb(exc.__traceback__)

assert len(tb1) == len(tb2) == len(tb3)

0 comments on commit 56085d7

Please sign in to comment.