Skip to content

Commit aef6ea3

Browse files
committed
Emit deprecation warning + deprecation doc + changelog
1 parent 9a57106 commit aef6ea3

File tree

6 files changed

+71
-7
lines changed

6 files changed

+71
-7
lines changed

changelog/9277.breaking.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
The ``pytest.Instance`` collector type has been removed.
2+
Importing ``pytest.Instance`` or ``_pytest.python.Instance`` returns a dummy type and emits a deprecation warning.
3+
See :ref:`instance-collector-deprecation` for details.

doc/en/deprecations.rst

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,25 @@ Deprecated Features
1818
Below is a complete list of all pytest features which are considered deprecated. Using those features will issue
1919
:class:`PytestWarning` or subclasses, which can be filtered using :ref:`standard warning filters <warnings>`.
2020

21+
.. _instance-collector-deprecation:
22+
23+
The ``pytest.Instance`` collector
24+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
25+
26+
.. versionremoved:: 7.0
27+
28+
The ``pytest.Instance`` collector type has been removed.
29+
30+
Previously, Python test methods were collected as :class:`~pytest.Class` -> ``Instance`` -> :class:`~pytest.Function`.
31+
Now :class:`~pytest.Class` collects the test methods directly.
32+
33+
Most plugins which reference ``Instance`` do so in order to ignore or skip it,
34+
using a check such as ``if isinstance(node, Instance): return``.
35+
Such plugins should simply remove consideration of ``Instance`` on pytest>=7.
36+
However, to keep such uses working, a dummy type has been instanted in ``pytest.Instance`` and ``_pytest.python.Instance``,
37+
and importing it emits a deprecation warning. This will be removed in pytest 8.
38+
39+
2140
.. _node-ctor-fspath-deprecation:
2241

2342
``fspath`` argument for Node constructors replaced with ``pathlib.Path``

src/_pytest/deprecated.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,11 @@
119119
"pytest.{func}(msg=...) is now deprecated, use pytest.{func}(reason=...) instead",
120120
)
121121

122+
INSTANCE_COLLECTOR = PytestDeprecationWarning(
123+
"The pytest.Instance collector type is deprecated and is no longer used. "
124+
"See https://docs.pytest.org/en/latest/deprecations.html#the-pytest-instance-collector",
125+
)
126+
122127
# You want to make some `__init__` or function "private".
123128
#
124129
# def my_private_function(some, args):

src/_pytest/python.py

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
from _pytest.config.argparsing import Parser
5959
from _pytest.deprecated import check_ispytest
6060
from _pytest.deprecated import FSCOLLECTOR_GETHOOKPROXY_ISINITPATH
61+
from _pytest.deprecated import INSTANCE_COLLECTOR
6162
from _pytest.fixtures import FuncFixtureInfo
6263
from _pytest.main import Session
6364
from _pytest.mark import MARK_GEN
@@ -868,14 +869,24 @@ def xunit_setup_method_fixture(self, request) -> Generator[None, None, None]:
868869
self.obj.__pytest_setup_method = xunit_setup_method_fixture
869870

870871

871-
# Instance used to be a node type between Class and Function. It has been
872-
# removed in pytest 7.0. Some plugins exist which reference `pytest.Instance`
873-
# only to ignore it; this dummy class keeps them working. This could probably
874-
# be removed at some point.
875-
class Instance:
872+
class InstanceDummy:
873+
"""Instance used to be a node type between Class and Function. It has been
874+
removed in pytest 7.0. Some plugins exist which reference `pytest.Instance`
875+
only to ignore it; this dummy class keeps them working. This will be removed
876+
in pytest 8."""
877+
876878
pass
877879

878880

881+
# Note: module __getattr__ only works on Python>=3.7. Unfortunately
882+
# we can't provide this deprecation warning on Python 3.6.
883+
def __getattr__(name: str) -> object:
884+
if name == "Instance":
885+
warnings.warn(INSTANCE_COLLECTOR, 2)
886+
return InstanceDummy
887+
raise AttributeError(f"module {__name__} has no attribute {name}")
888+
889+
879890
def hasinit(obj: object) -> bool:
880891
init: object = getattr(obj, "__init__", None)
881892
if init:

src/pytest/__init__.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@
4848
from _pytest.pytester import RunResult
4949
from _pytest.python import Class
5050
from _pytest.python import Function
51-
from _pytest.python import Instance
5251
from _pytest.python import Metafunc
5352
from _pytest.python import Module
5453
from _pytest.python import Package
@@ -77,6 +76,7 @@
7776

7877
set_trace = __pytestPDB.set_trace
7978

79+
8080
__all__ = [
8181
"__version__",
8282
"_fillfuncargs",
@@ -106,7 +106,6 @@
106106
"HookRecorder",
107107
"hookspec",
108108
"importorskip",
109-
"Instance",
110109
"Item",
111110
"LineMatcher",
112111
"LogCaptureFixture",
@@ -153,3 +152,12 @@
153152
"xfail",
154153
"yield_fixture",
155154
]
155+
156+
157+
def __getattr__(name: str) -> object:
158+
if name == "Instance":
159+
# The import emits a deprecation warning.
160+
from _pytest.python import Instance
161+
162+
return Instance
163+
raise AttributeError(f"module {__name__} has no attribute {name}")

testing/deprecated_test.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,3 +286,21 @@ def test_node_ctor_fspath_argument_is_deprecated(pytester: Pytester) -> None:
286286
parent=mod.parent,
287287
fspath=legacy_path("bla"),
288288
)
289+
290+
291+
@pytest.mark.skipif(
292+
sys.version_info < (3, 7),
293+
reason="This deprecation can only be emitted on python>=3.7",
294+
)
295+
def test_importing_instance_is_deprecated(pytester: Pytester) -> None:
296+
with pytest.warns(
297+
pytest.PytestDeprecationWarning,
298+
match=re.escape("The pytest.Instance collector type is deprecated"),
299+
):
300+
pytest.Instance
301+
302+
with pytest.warns(
303+
pytest.PytestDeprecationWarning,
304+
match=re.escape("The pytest.Instance collector type is deprecated"),
305+
):
306+
from _pytest.python import Instance # noqa: F401

0 commit comments

Comments
 (0)