Skip to content

Commit cb2ee5b

Browse files
committed
Improve deprecation message for class-scoped fixtures as instance methods (#14764)
Shorten the message with -Werror slightly via __tracebackhide__, point out the name of the fixture, and fix some grammar issues.
1 parent a53a4d9 commit cb2ee5b

4 files changed

Lines changed: 25 additions & 7 deletions

File tree

changelog/14774.deprecation.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Similarly to the deprecation of class-scoped fixtures defined as instance methods in pytest 9.1,
2+
*all* higher-scoped fixtures (``module``, ``package``, and ``session``) defined
3+
as instance methods are now deprecated.
4+
5+
They suffer from the same issue the original deprecation only fixed for
6+
class-scoped fixtures, see :issue:`10819` and :issue:`14011`.

src/_pytest/deprecated.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,13 @@
3434
"Use @pytest.fixture instead; they are the same."
3535
)
3636

37-
CLASS_FIXTURE_INSTANCE_METHOD = PytestRemovedIn10Warning(
38-
"Class-scoped fixture defined as instance method is deprecated.\n"
39-
"Instance attributes set in this fixture will NOT be visible to test methods,\n"
37+
CLASS_FIXTURE_INSTANCE_METHOD = UnformattedWarning(
38+
PytestRemovedIn10Warning,
39+
"Class-scoped fixtures defined as instance methods are deprecated.\n"
40+
"Instance attributes set in the {fixturename!r} fixture will NOT be visible to test methods,\n"
4041
"as each test gets a new instance while the fixture runs only once per class.\n"
41-
"Use @classmethod decorator and set attributes on cls instead.\n"
42-
"See https://docs.pytest.org/en/stable/deprecations.html#class-scoped-fixture-as-instance-method"
42+
"Use a @classmethod decorator below @pytest.fixture and set attributes on cls instead.\n"
43+
"See https://docs.pytest.org/en/stable/deprecations.html#class-scoped-fixture-as-instance-method",
4344
)
4445

4546
# This deprecation is never really meant to be removed.

src/_pytest/fixtures.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1274,6 +1274,10 @@ def resolve_fixture_function(
12741274
) -> _FixtureFunc[FixtureValue]:
12751275
"""Get the actual callable that can be called to obtain the fixture
12761276
value."""
1277+
1278+
def __tracebackhide__(e):
1279+
return issubclass(e.type, CLASS_FIXTURE_INSTANCE_METHOD.category)
1280+
12771281
fixturefunc = fixturedef.func
12781282
# The fixture function needs to be bound to the actual
12791283
# request.instance so that code working with "fixturedef" behaves
@@ -1287,7 +1291,12 @@ def resolve_fixture_function(
12871291
# classmethod: bound_to is the class itself (a type)
12881292
# instance method: bound_to is an instance (not a type)
12891293
if not isinstance(bound_to, type):
1290-
warnings.warn(CLASS_FIXTURE_INSTANCE_METHOD, stacklevel=2)
1294+
warnings.warn(
1295+
CLASS_FIXTURE_INSTANCE_METHOD.format(
1296+
fixturename=request.fixturename
1297+
),
1298+
stacklevel=2,
1299+
)
12911300

12921301
if instance is not None:
12931302
# Handle the case where fixture is defined not in a test class, but some other class

testing/deprecated_test.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,9 @@ def test_foo(self, fix):
104104
result = pytester.runpytest("-Werror::pytest.PytestRemovedIn10Warning")
105105
result.assert_outcomes(errors=1)
106106
result.stdout.fnmatch_lines(
107-
["*PytestRemovedIn10Warning: Class-scoped fixture defined as instance method*"]
107+
[
108+
"*PytestRemovedIn10Warning: Class-scoped fixtures defined as instance methods*"
109+
]
108110
)
109111

110112

0 commit comments

Comments
 (0)