Skip to content

Parent class marked fixture no longer reached with pytest 7.2 #10447

Closed

Description

@jaraco

Starting with the release of pytest 7.2, the distutils tests started failing (pypa/distutils#186).

I read the changelog for 7.2, but I don't see anything relevant.

The issue is likely due to some of these factors:

  • the test class is a subclass of another class
  • both classes are marked with usefixtures
  • The fixture on the subclass is reliant on the prior execution of the fixture in the parent class.

See the upstream bug for:

  • a detailed description of the bug or problem you are having
  • output of pip list from the virtual environment you are using
  • pytest and operating system versions

For consideration:

  • minimal example if possible

I haven't put together a minimal example yet as I'm still triaging the issue. Is there a known change with pytest 7.2 that was expected to change this behavior?

Activity

  1. jaraco commented on Oct 29, 2022

    @jaraco
    ContributorAuthor

    To be sure, these tests deserve a refactor. The tests are in this state because the project is transitioning away from unittest, but some artifacts remain.

  2. added
    topic: fixturesanything involving fixtures directly or indirectly
    plugin: unittestrelated to the unittest integration builtin plugin
    on Oct 29, 2022
  3. jaraco commented on Oct 29, 2022

    @jaraco
    ContributorAuthor

    Probably plugin:unittest is not relevant here, because the class hierarchy is no longer based on unittest.TestCase. I mention unittest because it explains why the fixtures reference request.instance as self (an artifact of the expectation when they did rely on TestCase).

  4. RonnyPfannschmidt commented on Oct 29, 2022

    @RonnyPfannschmidt
    Member

    this may be related to extraction of marks from the mro, (dint happenbefore, was aded recently

  5. jaraco commented on Jul 1, 2023

    @jaraco
    ContributorAuthor

    The MRO refactor was #7792 (31df38f). I've confirmed that the distutils fail on 31df38f but pass on 31df38f^1, confirming that change is the culprit.

    The changelog says:

    When inheriting marks from super-classes, the pytestmark attribute of the sub-class now only contains the marks directly applied to it. Previously, it also contained marks from its super-classes.

    That implies that it's intentional that previously reachable marks are now intentionally ignored.

    I'm not sure why that wouldn't be a breaking change.

    Is there any chance pytest will restore support for this use-case? Is there a way to apply a fixture at a superclass and have it take effect in a subclass?

  6. RonnyPfannschmidt commented on Jul 1, 2023

    @RonnyPfannschmidt
    Member

    The markers should take effect as all of them should land in the node for the class, I'll have to investigate the order difference

  7. jaraco commented on Jul 1, 2023

    @jaraco
    ContributorAuthor

    In that case, let me put together a more minimal repro.

  8. jaraco commented on Jul 1, 2023

    @jaraco
    ContributorAuthor

    Good news. A minimal repro was easy and I learned something:

     draft @ cat test_something.py
    import pytest
    
    @pytest.fixture
    def add_attr1(request):
        request.instance.attr1 = object()
    
    
    @pytest.fixture
    def add_attr2(request):
        request.instance.attr2 = request.instance.attr1
    
    
    @pytest.mark.usefixtures('add_attr1')
    class Parent:
        pass
    
    
    @pytest.mark.usefixtures('add_attr2')
    class TestThings(Parent):
        def test_attrs(self):
            self.attr1
            self.attr2
     draft @ pip-run 'pytest@git+https://github.com/pytest-dev/pytest@31df38f6a79b0734be3c1386eb7df6512b1a321b^1' -- -m pytest
      WARNING: Did not find branch or tag '31df38f6a79b0734be3c1386eb7df6512b1a321b^1', assuming revision or ref.
    ========================================================================= test session starts ==========================================================================
    platform darwin -- Python 3.11.4, pytest-7.2.0.dev331+g15ac0349, pluggy-1.2.0
    rootdir: /Users/jaraco/draft
    plugins: anyio-3.6.2
    collected 1 item                                                                                                                                                       
    
    test_something.py .                                                                                                                                              [100%]
    
    ========================================================================== 1 passed in 0.00s ===========================================================================
     draft @ pip-run 'pytest@git+https://github.com/pytest-dev/pytest@31df38f6a79b0734be3c1386eb7df6512b1a321b' -- -m pytest
    ========================================================================= test session starts ==========================================================================
    platform darwin -- Python 3.11.4, pytest-7.2.0.dev338+g31df38f6, pluggy-1.2.0
    rootdir: /Users/jaraco/draft
    plugins: anyio-3.6.2
    collected 1 item                                                                                                                                                       
    
    test_something.py E                                                                                                                                              [100%]
    
    ================================================================================ ERRORS ================================================================================
    _______________________________________________________________ ERROR at setup of TestThings.test_attrs ________________________________________________________________
    
    request = <SubRequest 'add_attr2' for <Function test_attrs>>
    
        @pytest.fixture
        def add_attr2(request):
    >       request.instance.attr2 = request.instance.attr1
    E       AttributeError: 'TestThings' object has no attribute 'attr1'
    
    test_something.py:10: AttributeError
    ======================================================================= short test summary info ========================================================================
    ERROR test_something.py::TestThings::test_attrs - AttributeError: 'TestThings' object has no attribute 'attr1'
    =========================================================================== 1 error in 0.02s ===========================================================================
    

    The issue isn't that the fixture on the parent class isn't being called, but that the fixtures are called in a different order with the fixture on the child being called before the fixture on the parent. Independent of this specific example, I'd expect fixtures on more basic classes to be called first, as the child (derived) class is liable to depend on behavior from the parent but not vice-versa (from a modeling perspective, the parent class is largely unaware of the child classes).

  9. RonnyPfannschmidt commented on Jul 1, 2023

    @RonnyPfannschmidt
    Member

    Found the bug

    https://github.com/pytest-dev/pytest/blob/main/src/_pytest/mark/structures.py#L377 is missing a reversed when considering the mro

  10. added a commit that references this issue on Jul 1, 2023
    43fd1fe
  11. added 2 commits that reference this issue on Jul 1, 2023
    d909411
    c207f7c
  12. RonnyPfannschmidt commented on Jul 1, 2023

    @RonnyPfannschmidt
    Member

    @jaraco seems like our timing was unfortuate

  13. jaraco commented on Jul 1, 2023

    @jaraco
    ContributorAuthor

    No problem. Happy to consolidate. I'll fix the mypy bug in mine and copy the test from yours, but feel free to choose the PR you prefer.

  14. added a commit that references this issue on Jul 1, 2023
    a8eb819
  15. RonnyPfannschmidt commented on Jul 1, 2023

    @RonnyPfannschmidt
    Member

    @jaraco im under the impression that the content would practically be the same, so i'd just go with mine

  16. added a commit that references this issue on Jul 1, 2023
    561f1a9
  17. added a commit that references this issue on Jul 2, 2023
    f9410fd
  18. added a commit that references this issue on Oct 24, 2023
    6596ba3
  19. added a commit that references this issue on Oct 24, 2023
    44ad1c9
  20. added 3 commits that reference this issue on Apr 13, 2026
    d2640fe
    a341aa3
    02eab04
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

    plugin: unittestrelated to the unittest integration builtin plugintopic: fixturesanything involving fixtures directly or indirectly

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions