From 4ef8c1a4ccf41cfa0c9303c3d248cee08ab735af Mon Sep 17 00:00:00 2001 From: Ronny Pfannschmidt Date: Sun, 14 Mar 2021 23:01:58 +0100 Subject: [PATCH] issue a warning when Items and Collector form a diamond addresses #8435 --- changelog/8447.deprecation.rst | 4 ++++ src/_pytest/nodes.py | 14 ++++++++++++++ testing/test_nodes.py | 10 ++++++++++ 3 files changed, 28 insertions(+) create mode 100644 changelog/8447.deprecation.rst diff --git a/changelog/8447.deprecation.rst b/changelog/8447.deprecation.rst new file mode 100644 index 00000000000..098ca89be75 --- /dev/null +++ b/changelog/8447.deprecation.rst @@ -0,0 +1,4 @@ +Warn when inheritance is used to bring Collectors into Items, +it was never sanely supported and triggers hard to debug errors. + +Instead of inheritance composition should be used. diff --git a/src/_pytest/nodes.py b/src/_pytest/nodes.py index 99b7eb1a61c..f5774a728e2 100644 --- a/src/_pytest/nodes.py +++ b/src/_pytest/nodes.py @@ -34,6 +34,7 @@ from _pytest.pathlib import absolutepath from _pytest.pathlib import commonpath from _pytest.store import Store +from _pytest.warning_types import PytestWarning if TYPE_CHECKING: # Imported here due to circular import. @@ -600,6 +601,19 @@ class Item(Node): nextitem = None + def __init_subclass__(cls): + problems = ", ".join( + base.__name__ for base in cls.__bases__ if issubclass(base, Collector) + ) + if problems: + warnings.warn( + f"{cls.__name__} is a Item subclass and should not be a collector.\n" + f"however its bases {problems} are collectors\n" + "please split the collection and the items into 2 node types\n" + "TODO: doc link", + PytestWarning, + ) + def __init__( self, name, diff --git a/testing/test_nodes.py b/testing/test_nodes.py index fbdbce3950d..de6c4595c96 100644 --- a/testing/test_nodes.py +++ b/testing/test_nodes.py @@ -37,6 +37,16 @@ def test_node_from_parent_disallowed_arguments() -> None: nodes.Node.from_parent(None, config=None) # type: ignore[arg-type] +def test_subclassing_node_with_item_warns() -> None: + + with pytest.warns( + PytestWarning, match="SoWrong is a Item subclass and should not be a collector" + ): + + class SoWrong(nodes.Item, nodes.File): + pass + + @pytest.mark.parametrize( "warn_type, msg", [(DeprecationWarning, "deprecated"), (PytestWarning, "pytest")] )