File tree Expand file tree Collapse file tree 3 files changed +79
-1
lines changed
Expand file tree Collapse file tree 3 files changed +79
-1
lines changed Original file line number Diff line number Diff line change 1+ If a test raises an ``ExceptionGroup `` (or nested ``ExceptionGroup ``\ s) with only
2+ a single 'leaf' exception from ``pytest.xfail() `` or ``pytest.skip() ``\ , we now
3+ unwrap it to have the desired effect on Pytest. ``ExceptionGroup ``\ s with two or
4+ more leaf exceptions, even of the same type, are not changed and will be treated
5+ as ordinary test failures.
6+
7+ See `pytest-dev/pytest#9680 <https://github.com/pytest-dev/pytest/issues/9680 >`__
8+ for design discussion. This feature is particularly useful if you've enabled
9+ `the new strict_exception_groups=True option
10+ <https://trio.readthedocs.io/en/stable/reference-core.html#strict-versus-loose-exceptiongroup-semantics> `__.
Original file line number Diff line number Diff line change @@ -74,3 +74,52 @@ def test_invalid():
7474 result = testdir .runpytest ()
7575
7676 result .assert_outcomes (errors = 1 )
77+
78+
79+ def test_skip_and_xfail (testdir ):
80+
81+ testdir .makepyfile (
82+ """
83+ import functools
84+ import pytest
85+ import trio
86+
87+ trio.run = functools.partial(trio.run, strict_exception_groups=True)
88+
89+ @pytest.mark.trio
90+ async def test_xfail():
91+ pytest.xfail()
92+
93+ @pytest.mark.trio
94+ async def test_skip():
95+ pytest.skip()
96+
97+ async def callback(fn):
98+ fn()
99+
100+ async def fail():
101+ raise RuntimeError
102+
103+ @pytest.mark.trio
104+ async def test_xfail_and_fail():
105+ async with trio.open_nursery() as nursery:
106+ nursery.start_soon(callback, pytest.xfail)
107+ nursery.start_soon(fail)
108+
109+ @pytest.mark.trio
110+ async def test_skip_and_fail():
111+ async with trio.open_nursery() as nursery:
112+ nursery.start_soon(callback, pytest.skip)
113+ nursery.start_soon(fail)
114+
115+ @pytest.mark.trio
116+ async def test_xfail_and_skip():
117+ async with trio.open_nursery() as nursery:
118+ nursery.start_soon(callback, pytest.skip)
119+ nursery.start_soon(callback, pytest.xfail)
120+ """
121+ )
122+
123+ result = testdir .runpytest ("-s" )
124+
125+ result .assert_outcomes (skipped = 1 , xfailed = 1 , failed = 3 )
Original file line number Diff line number Diff line change 1010import trio
1111from trio .abc import Clock , Instrument
1212from trio .testing import MockClock
13+ from _pytest .outcomes import Skipped , XFailed
1314
1415if sys .version_info [:2 ] < (3 , 11 ):
1516 from exceptiongroup import BaseExceptionGroup
@@ -343,7 +344,25 @@ def wrapper(**kwargs):
343344 f"Expected at most one Clock in kwargs, got { clocks !r} "
344345 )
345346 instruments = [i for i in kwargs .values () if isinstance (i , Instrument )]
346- return run (partial (fn , ** kwargs ), clock = clock , instruments = instruments )
347+ try :
348+ return run (partial (fn , ** kwargs ), clock = clock , instruments = instruments )
349+ except BaseExceptionGroup as eg :
350+ queue = [eg ]
351+ leaves = []
352+ while queue :
353+ ex = queue .pop ()
354+ if isinstance (ex , BaseExceptionGroup ):
355+ queue .extend (ex .exceptions )
356+ else :
357+ leaves .append (ex )
358+ if len (leaves ) == 1 :
359+ if isinstance (leaves [0 ], XFailed ):
360+ pytest .xfail ()
361+ if isinstance (leaves [0 ], Skipped ):
362+ pytest .skip ()
363+ # Since our leaf exceptions don't consist of exactly one 'magic'
364+ # skipped or xfailed exception, re-raise the whole group.
365+ raise
347366
348367 return wrapper
349368
You can’t perform that action at this time.
0 commit comments