Skip unwrapping plugin attributes that cannot hide a fixture - #14885
Open
aryansk wants to merge 1 commit into
Open
Skip unwrapping plugin attributes that cannot hide a fixture#14885aryansk wants to merge 1 commit into
aryansk wants to merge 1 commit into
Conversation
parsefactories() called _check_for_wrapped_fixture() - which runs inspect.unwrap() - on every attribute of every registered plugin, even though most plugin attributes (plain functions, classes, modules and values) can never contain a fixture definition. In a default session most registered plugins define no fixtures at all, so the scan is pure overhead repeated for every Config that is built (e.g. thousands of times by pytester-based test suites). Only attributes which could hide a fixture definition behind another decorator need the unwrap: staticmethod/classmethod descriptors and objects with a __wrapped__ chain (including a bare FixtureFunctionDefinition, which sets __wrapped__ via functools.update_wrapper). Everything else is skipped. safe_getattr is used so that objects with a broken __getattr__ (pytest#214) do not raise. Fix pytest-dev#14877 🤖 Generated with Codebuff Co-Authored-By: Codebuff <noreply@codebuff.com>
RonnyPfannschmidt
approved these changes
Aug 15, 2026
RonnyPfannschmidt
left a comment
Member
There was a problem hiding this comment.
this will severely downplay the effect of a different speefup im still working on, but thats a good thing
Author
|
Thanks Ronny — appreciated. Happy to adjust if the in-flight speedup changes the tradeoff; the focused fixture-wrap check stays as is unless you'd prefer otherwise. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fix #14877.
FixtureManager.parsefactories()calls_check_for_wrapped_fixture()— which runsinspect.unwrap()— on every attribute of every registered plugin, even though most plugin attributes (plain functions, classes, modules, and values) can never contain a fixture definition. In a default session most registered plugins define no fixtures, so the scan is pure overhead repeated for everyConfigthat is built (thousands of times in pytest's ownpytester-based test suite).Change
Only attributes which could hide a fixture definition behind another decorator need the unwrap:
staticmethod/classmethoddescriptors (e.g.@classmethodabove@pytest.fixture), and__wrapped__chain (e.g. fromfunctools.wraps; a bareFixtureFunctionDefinitionalso sets__wrapped__viafunctools.update_wrapper, so genuine fixtures still take this path — where_check_for_wrapped_fixtureis a cheap no-op).Everything else is skipped.
safe_getattr(nothasattr) is used for the__wrapped__probe so that objects with a broken__getattr__do not raise (the existingtest_parsefactories_evil_objects_issue214guard, pytest#214).The existing warning behaviour is preserved exactly: all four wrapped-fixture warning scenarios (
@staticmethod,@classmethod, andfunctools.wraps-style custom decorators, with or without an intervening@classmethod) still emit their warnings, and the tests for them pass unchanged.Validation
test_parsefactories_only_unwraps_attributes_that_can_hide_fixturesasserts that plain values, methods, and functions are never unwrapped while fixture-bearing attributes and descriptors still are.3731 passed(the only failure,test_error_diffs[Compare attrs classes], is a pre-existing attrs-version issue onmain).parsefactorieson a plugin-like object with 600 plain attributes: 0.90 ms → 0.49 ms per scan (~45% faster).pre-commit(incl. mypy) passes on the changed files.Note
This issue and this contribution were developed with AI assistance; the change itself is small and scoped, and the above describes exactly what it does.