Skip to content

Double pytest.skip leads to failure #13537

Closed

Description

@ego-thales

Hello everyone.

I think the following is a bug.

@pytest.fixture
def fixA():
    yield
    pytest.skip(reason="A")

@pytest.fixture
def fixB():
    yield
    pytest.skip(reason="B")

def test_skip(fixA, fixB):  # FAILS
    assert True

Gives the following error report (removed tracebacks).

____________________________ ERROR at teardown of test_skip _____________________________
  + Exception Group Traceback (most recent call last):
  | <traceback>
  | BaseExceptionGroup: errors while tearing down <Function test_skip> (2 sub-exceptions)
  +-+---------------- 1 ----------------
    | <traceback>
    | Skipped: A
    +---------------- 2 ----------------
    | <traceback>
    | Skipped: B
    +------------------------------------

Maybe pytest checks for the error raised being of the type of skips, and thus here it bugs because it's an ExceptionGroup and not a skip type? I'm just very wildly guessing, I don't know the internals of pytest.

Activity

  1. changed the title [-]Double `pytest.skip` lead to failure[/-] [+]Double `pytest.skip` leads to failure[/+] on Jun 18, 2025
  2. The-Compiler commented on Jun 18, 2025

    @The-Compiler
    Member

    In pytest 7.2.2 (or when removing fixB), this results in 1 passed, 1 skipped (which is somewhat confusing but another long-standing issue).

    With pytest 7.3.0 and later, this errors in the same way you mention. Bisected to 3a68c08:

    And I think your guess is spot-on, e.g. around here:

    skip_exceptions = [Skipped]
    unittest = sys.modules.get("unittest")
    if unittest is not None:
    skip_exceptions.append(unittest.SkipTest)
    if isinstance(call.excinfo.value, tuple(skip_exceptions)):
    outcome = "skipped"
    r_ = collector._repr_failure_py(call.excinfo, "line")
    assert isinstance(r_, ExceptionChainRepr), repr(r_)
    r = r_.reprcrash
    assert r
    longrepr = (str(r.path), r.lineno, r.message)
    else:
    outcome = "failed"

    I suspect this might also happen with other outcome exceptions. Maybe we should immediately raise the first outcome exception as a special case rather than grouping those? Perhaps conditionally as long as there are no other non-outcome exceptions that happened?

    cc @Zac-HD @jakkdl who did a lot of work around exception groups

  3. added
    type: bugproblem that needs to be addressed
    topic: tracebacksrelated to displaying and handling of tracebacks
    type: regressionindicates a problem that was introduced in a release which was working previously
    on Jun 18, 2025
  4. RonnyPfannschmidt commented on Jun 18, 2025

    @RonnyPfannschmidt
    Member

    We should consider exception group's with only skip as skip

  5. ego-thales commented on Jun 18, 2025

    @ego-thales
    Author

    Ok great!

    Maybe we should immediately raise the first outcome exception as a special case rather than grouping those? Perhaps conditionally as long as there are no other non-outcome exceptions that happened?

    I was thinking about this and I don't think the desired behaviour is trivial to define. For example, we might want to skip if there are only skips, but we might also want to allow fixtures to skip even if an inner fixture failed? Like a kind of "catching fixture". It seems far fetched, but I think there's potentially something to clarify here.

    Also, we might want to skip at the first skip encountered, OR we might want to allow outermost fixture to still fail the test even if an inner fixture skipped it?

    So as I see it, it's a discussion that needs to happen.

  6. RonnyPfannschmidt commented on Jun 18, 2025

    @RonnyPfannschmidt
    Member

    The groupings was added so exceptions no longer get lost

    Now we need to account for that in places

  7. Zac-HD commented on Jun 18, 2025

    @Zac-HD
    Member
    if isinstance(exc := call.excinfo.value, tuple(skip_exceptions)) or (
        isinstance(exc, BaseExceptionGroup) and exc.subgroup(skip_exceptions)
    ):

    once we drop Python 3.10, the new except* syntax should also make it easier.

  8. RonnyPfannschmidt commented on Jun 20, 2025

    @RonnyPfannschmidt
    Member

    I did a quick excursion to exitstack

    Exitstack nests the errors by manipulation of the context so it behaves as if it was nested

    We should consider whether we want that or groups in general

    Based on the behavior of exception groups i slightly prefer the idea of eventually handling those from groups

  9. Zac-HD commented on Jun 20, 2025

    @Zac-HD
    Member

    We'll need to handle ExceptionGroups anyway, in case the user calls pytest.skip() from inside an asyncio.TaskGroup context manager (among other cases)

  10. RonnyPfannschmidt commented on Jun 20, 2025

    @RonnyPfannschmidt
    Member

    Good point

  11. gomri15 commented on Sep 18, 2025

    @gomri15
    Contributor

    would love to take a crack at this now that i've made some progress with pytest.exit().
    could you assign it to me and in general should i wait to be assigned to something before i start working on it?

  12. Zac-HD commented on Sep 18, 2025

    @Zac-HD
    Member

    open source projects almost never assign issues - it's very rare to see duplicate PRs for an issue more than a few days old, and so it's not worth the overhead in notifications etc. Which means, feel free to just open a PR!

  13. added a commit that references this issue on Sep 21, 2025
    91f73f4
  14. 2 remaining items

  15. added 3 commits that reference this issue on Sep 21, 2025
    0380548
    90fba0d
    959a89f
  16. added 5 commits that reference this issue on Oct 15, 2025
    6ed264c
    9adef4b
    2d37732
    11ad3fb
    ff07ff6
  17. added a commit that references this issue on Oct 28, 2025
    e26c0ae
  18. added a commit that references this issue on Aug 31, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    topic: tracebacksrelated to displaying and handling of tracebackstype: bugproblem that needs to be addressedtype: regressionindicates a problem that was introduced in a release which was working previously

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions