Skip to content

Commit

Permalink
fixup: correct missed legacy codepath
Browse files Browse the repository at this point in the history
  • Loading branch information
RonnyPfannschmidt committed Nov 3, 2024
1 parent 4cf313d commit ed5b22b
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 7 deletions.
9 changes: 5 additions & 4 deletions changelog/544.bugfix.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
Correctly pass StopIteration trough wrappers.
Correctly pass :class:`StopIteration` trough hook wrappers.

Raising a StopIteration in a generator triggers a RuntimeError.
If the RuntimeError of a generator has the passed in StopIteration as cause
resume with that StopIteration as normal exception instead of failing with the RuntimeError.
Raising a :class:`StopIteration` in a generator triggers a :class:`RuntimeError`.

If the :class:`RuntimeError` of a generator has the passed in :class:`StopIteration` as cause
resume with that :class:`StopIteration` as normal exception instead of failing with the :class:`RuntimeError`.
14 changes: 13 additions & 1 deletion src/pluggy/_callers.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ def _multicall(
try:
teardown.throw(exception) # type: ignore[union-attr]
except RuntimeError as re:
# Stopiteration from generator causes RuntimeError even for corutine usage
if (
isinstance(exception, StopIteration)
and re.__cause__ is exception
Expand Down Expand Up @@ -174,7 +175,18 @@ def _multicall(
else:
try:
if outcome._exception is not None:
teardown.throw(outcome._exception)
try:
teardown.throw(outcome._exception)
except RuntimeError as re:
# Stopiteration from generator causes RuntimeError even for corutine usage
if (
isinstance(outcome._exception, StopIteration)
and re.__cause__ is outcome._exception
):
teardown.close()
continue
else:
raise
else:
teardown.send(outcome._result)
# Following is unreachable for a well behaved hook wrapper.
Expand Down
9 changes: 7 additions & 2 deletions testing/test_multicall.py
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,8 @@ def m2():
]


def test_wrapper_stopiteration_passtrough():
@pytest.mark.parametrize("has_hookwrapper", [True, False])
def test_wrapper_stopiteration_passtrough(has_hookwrapper: bool) -> None:
out = []

@hookimpl(wrapper=True)
Expand All @@ -427,14 +428,18 @@ def wrap():
finally:
out.append("wrap done")

@hookimpl(wrapper=not has_hookwrapper, hookwrapper=has_hookwrapper)
def wrap_path2():
yield

@hookimpl
def stop():
out.append("stop")
raise StopIteration

with pytest.raises(StopIteration):
try:
MC([stop, wrap], {})
MC([stop, wrap, wrap_path2], {})
finally:
out.append("finally")

Expand Down

0 comments on commit ed5b22b

Please sign in to comment.