Skip to content

pytest-10 deprecation prep: class-scoped fixture as instance method #383

Description

@davidlabianca

Summary

pytest 9.1.0 emits PytestRemovedIn10Warning for a class-scoped fixture defined as an instance method. This is the only warning the #380 bump surfaces, and it is not caused by #380 — the bump just made the pre-existing deprecation visible. It is a warning today; it will be a collection error in pytest 10.

scripts/hooks/tests/test_frameworks_schema_v027.py::TestExistingEntriesStillValidate::test_all_six_entries_present_in_yaml

  _pytest/fixtures.py:1312: PytestRemovedIn10Warning: Class-scoped fixture defined as
  instance method is deprecated. Instance attributes set in this fixture will NOT be
  visible to test methods, as each test gets a new instance while the fixture runs only
  once per class. Use @classmethod decorator and set attributes on cls instead.
  
See https://docs.pytest.org/en/stable/deprecations.html#class-scoped-fixture-as-instance-method

Upstream reference: pytest issue #10819.

Location

scripts/hooks/tests/test_frameworks_schema_v027.py:1285

class TestExistingEntriesStillValidate:
    @pytest.fixture(scope="class")
    def framework_entries(self, frameworks_yaml_data: dict) -> list:
        """Individual framework entries from frameworks.yaml."""
        entries = frameworks_yaml_data.get("frameworks", [])
        if not entries:
            pytest.fail("frameworks.yaml has no 'frameworks' entries")
        return entries

Consumed by three methods in the same class: test_all_six_entries_present_in_yaml (:1293), and the two at :1320 and :1339. Its only dependency, frameworks_yaml_data (:260), is module-scoped — wider than class, so it is compatible with either fix below.

note: This is the only instance of the anti-pattern in the suite (grep -rln 'scope="class"' scripts/hooks/tests/ returns just this file).

Why it's harmless now but must be fixed

  • The fixture is a pure read of already-loaded module data and returns a value; it sets no instance attributes, so the actual misbehavior the warning guards against (state set on a throwaway instance) does not occur here. Tests pass correctly.
  • The repo sets no filterwarnings = error, so the warning does not fail CI today.
  • But pytest 10 removes the behavior entirely — at that point this becomes a collection error and the three tests (and likely the whole module) fail. Fixing now is cheap and removes the only blocker to a future filterwarnings = error posture.

Proposed fix

Match pytest's own guidance: @classmethod

@pytest.fixture(scope="class")
@classmethod
def framework_entries(cls, frameworks_yaml_data: dict) -> list:
    entries = frameworks_yaml_data.get("frameworks", [])
    if not entries:
        pytest.fail("frameworks.yaml has no 'frameworks' entries")
    return entries

Preserves the once-per-class evaluation intent. Valid because the requested
frameworks_yaml_data is module-scoped (≥ class scope).

Verification

PYTHONPATH=./scripts/hooks pytest scripts/hooks/tests/test_frameworks_schema_v027.py -W error::PytestRemovedIn10Warning -q
  • Pass: module runs clean with the deprecation promoted to an error (proves it's gone).
  • Then a full-suite run should report 0 warnings from this source.

Acceptance criteria

  • framework_entries no longer triggers PytestRemovedIn10Warning.
  • All three consuming tests still pass with identical assertions.
  • Full suite reports zero warnings from this source.
  • (Optional, separate) consider whether to adopt filterwarnings = error in [tool.pytest.ini_options] now that the suite is warning-clean, to catch the next deprecation at the source instead of in a dependency-bump review.

References

Metadata

Metadata

Assignees

No one assigned

    Type

    No fields configured for Bug.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions